ts能够用于node环境和web环境,或者说在es module出来以前,大部分的包都是遵循commonjs的,而这些遵循commonjs的包如今大多还存在与nodejs当中,也是nodejs迟迟尚未全面支持esm的缘由。那么ts怎么兼容commonjs和esm包呢?html
若是你不经常使用ts或者是没有在nodejs中用过ts,那么看到ts 官方的推荐写法,必定会傻眼,居然是import和require混用……
文件模块的导入node
咱们要理解ts为何有这么独特的推荐写法,先来回顾一下commonjd和esm的相关知识,而且考虑在ts中他们的互换性react
咱们有一个commonjs文件git
// my-module.js module.exports = { foo, bar }
两种方式引入而且解构,好像没有什么不一样github
// index.ts // cjs const { foo, bar } = require('my-module') // esm import { foo, bar } from 'my-module'
可是咱们来看下面这一组web
// module export const foo = 1 export const bar = 2 export default () => {} // esm import { foo } from 'module' import func from 'module'`
// module module.exports = { foo: 1, bar: 2, default: () => {} } // cjs const module = require('module') const foo = module.foo const func = module.default
所以若是咱们都是用default的这个function 在commonjs中须要点操做module.default才能够获取到。
好比考虑互操做性,在react中,typescript
import React from 'react' 至关于只导入了default这个属性 const {default: React} = require('react')
所以2018年以前咱们在用ts引入React的为了保持一致性会这样写import * as React from 'react'
来获取module.exports中的全部内容。ui
所以在导入commonjs模块的时候ts除了有require混合的写法也能够用import *
的写法typescript-import-as-vs-import-requirethis
ts2.7出了一个esModuleInterop的配置,支持import d from "cjs"
support-for-import-d-from-cjs-from-commonjs-modules-with---esmoduleinterospa
来简单看下ts如何作到兼容一致性
// common.js module.exports = { default: function greeter(person) { return "Hello, " + person; }, person: "common" }; // esm.js export default function greeter(person) { return "Hello, " + person; } export const person = "esm"; // index.ts import common from "./common"; import esm from "./esm"; const common1 = require("./common"); const esm1 = require("./esm"); import * as common2 from "./common"; import * as esm2 from "./esm"; console.log(common, common1, common2); console.log(esm, esm1, esm2);
esModuleInterop为false的时候编译的代码
"use strict"; exports.__esModule = true; var common_1 = require("./common"); var esm_1 = require("./esm"); var common1 = require("./common"); var esm1 = require("./esm"); var common2 = require("./common"); var esm2 = require("./esm"); console.log(common_1["default"], common1, common2); console.log(esm_1["default"], esm1, esm2); //[Function: greeter] { default: [Function: greeter], person: 'common' } { default: [Function: greeter], person: 'common' } //[Function: greeter] { default: [Function: greeter], person: 'esm' } { default: [Function: greeter], person: 'esm' }
能够观察到import common from "./common"
;输入的结果只有default的方法,跟const common1 = require("./common");
输出的结果不同,并不能保持一致性,这也是前面提到为何咱们要import *
或者import 和require同处一等式的缘由
esModuleInterop为true时候的编译代码
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; exports.__esModule = true; var common_1 = __importDefault(require("./common")); var esm_1 = __importDefault(require("./esm")); var common1 = require("./common"); var esm1 = require("./esm"); var common2 = __importStar(require("./common")); var esm2 = __importStar(require("./esm")); console.log(common_1["default"], common1, common2); console.log(esm_1["default"], esm1, esm2); // { default: [Function: greeter], person: 'common' } { default: [Function: greeter], person: 'common' } { default: { default: [Function: greeter], person: 'common' }, person: 'common' } // [Function: greeter] { default: [Function: greeter], person: 'esm' } { default: [Function: greeter], person: 'esm' }
esModuleInterop 为true,咱们能够看到加入了__importDefault和__importStar判断引入的模块是否是esm模块再作封装,import common from "./common"
;输入的结果只有default的方法,跟const common1 = require("./common");
输出的结果保持了一致性
1.在ts2.7以后的项目+esModuleInterop不须要去考虑引入包的一些兼容
2.即便在ts2.7以前的项目最好也不要用import和require混用的写法,用import * ,由于esm终将是大流
https://stackoverflow.com/que...
https://palantir.github.io/ts...