TypeScript 中的多种 import与export

333 阅读2分钟

TypeScript 中不同 import 的含义,最典型的就是下面的 import 语法:

import * as path from 'path'

JavaScript 的模块化方案,在历史的演进中,有多种导出模块的方式:exportsmodule.exportsexportexport default。 在 nodejs 中内置的模块遵循的都是 CommonJS 规范,语法为 module.exports 和 exports。 // 模块中的 exports 变量指向 module.exports

module.exports = function () { }

exports.site = 'tasaid.com'

module.exports.name = 'linkFly'

在 ECMAScript 6 中又新增了语法 export 和 export default:

大名鼎鼎的 JavaScript 转码编译器 babel 针对 ECMAScript 6 新增的 export default 语法,搞了个 babel-plugin-transform-es2015-modules-commonjs 的转换插件,用于将 ECMAScript 6 转码为 CommonJs 规范的语法:

源码: export default 42;

编译后:

Object.defineProperty(exports, "__esModule", {
value: true
});

exports.default = 42;

到这里,我们看到有三种 export 默认值的语法: // commonjs
module.exports = function () {}

// babel 转码
exports.default = function () {}

// es6
export default function () {}

TypeScript 中的 import

在 TypeScript 中,也有多种 import 的方式。

// commonjs 模块
import * as xx from 'xx'

// es6 模块
import xx from 'xx'

// commonjs 模块,类型声明为 export = xx
import xx = require('xx')

// 没有类型声明,默认导入 any 类型
const xx = require('xx')

在 tsconfig.json 中,allowSyntheticDefaultImports 会影响到 import 语法的类型检查规则,这个下面再说。

import * as xx from ‘xx’

import * as xx from 'xx' 的语法来一般都是用来导入使用 module.exports 导出的模块。

因为 nodejs 中的模块大部分都是通过 module.exportsexports.xx 语法进行导出的。

import xx from ‘xx’

默认情况下,import xx from 'xx' 的语法只适用于 ECMAScript 6 的 export default 导出:

模块 foo:

export default function () {
console.log('tasaid.com')
}

ES6 模块的导入: export default function () {
console.log('tasaid.com')
}

而前面我们说了,babel 会将 es6 的模块的 export default 语法编译为 exports.default 语法。

而 TypeScript 默认是不识别这种语法的,如果一个模块的导出是 exports.default 导出,如果使用 import xx from 'xx' 的语法导入是会报错的。

image.png

所以在 tsconfig.json 中,有个 allowSyntheticDefaultImports 选项,就是针对这种语法做兼容。

如果设定 allowSyntheticDefaultImports 为 true,则检测导入的模块是否是 ES6 模块,如果不是,则查找模块中是否有 exports.default 导出。

从而达到针对 exports.default 的兼容。

image.png

我个人是不推荐打开 allowSyntheticDefaultImports 选项的,一般情况下我采取的方式是将 deafult 重新命名:

import { default as foo } from 'foo'

import xx = require(‘xx’)

import xx = require('xx') 是用来导入 commonjs 模块的库,特殊的地方在于这个库的类型声明是 export = xx 这种方式导出的:

foo.js 源码:

module.exports = () => {
console.log('tasaid.com')
}

foo.d.ts 类型声明文件源码:

declare function foo(): void;
export = foo

bar.ts 引用:

import foo = require('./foo')

foo()

image.png

const xx = require(‘xx’)

当一个模块没有类型声明文件的时候,可以使用 commonjs 原始的 require() 方式来导入模块,这样会默认该模块为 any。