TypeScript 中的多種 import 解義

JavaScript 中有多種 export 的方式,而 TypeScript 中針對這種狀況作了多種 import 語法,最多見的就是 import * as path from 'path' 這種。這篇文章主要來說解 TypeScript 中不一樣的 import 具備什麼意義。javascript

原文首發於個人我的網站:據說 - https://tasaid.com,推薦在個人網站閱讀更多技術文章。html

前端開發 QQ 羣:377786580

從 export 提及

有不少朋友都問過我關於 TypeScript 中不一樣 import 的含義,最典型的就是下面的 import 語法:前端

import * as path from 'path'

很多人疑問這句代碼到底是什麼意思,這裏咱們要先從 js 的 export 開始說。java

首先,JavaScript 的模塊化方案,在歷史的演進中,有多種導出模塊的方式:exportsmodule.exportsexportexport defaultnode

在 nodejs 中內置的模塊遵循的都是 CommonJS 規範,語法爲 module.exportsexportsgit

// 模塊中的 exports 變量指向 module.exports
// 這篇文章不會深刻講解 module.exports 和 exports 的關係

module.exports = function () { }

exports.site = 'https://tasaid.com'

module.exports.name = 'linkFly'

例如 nodejs 內置的 events 模塊的源碼:es6

clipboard.png

ECMAScript 6 中又新增了語法 exportexport default:github

export default function () { }

export const site = 'https://tasaid.com'

export const name = 'linkFly'

到這裏畫風還比較正常,而大名鼎鼎的 JavaScript 轉碼編譯器 babel 針對 ECMAScript 6 新增的 export default 語法,搞了個 babel-plugin-transform-es2015-modules-commonjs 的轉換插件,用於將 ECMAScript 6 轉碼爲 CommonJs 規範的語法:typescript

源碼:json

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 導出的模塊。

import * as path from 'path'

由於 nodejs 中的模塊大部分都是經過 module.exportsexports.xx 語法進行導出的。

import xx from 'xx'

默認狀況下,import xx from 'xx' 的語法只適用於 ECMAScript 6 的 export default 導出:

模塊 foo:

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

ES6 模塊的導入:

import foo from './foo'
foo()

而前面咱們說了,babel 會將 es6 的模塊的 export default 語法編譯爲 exports.default 語法。

而 TypeScript 默認是不識別這種語法的,若是一個模塊的導出是 exports.default 導出,若是使用 import xx from 'xx' 的語法導入是會報錯的。

clipboard.png

因此在 tsconfig.json 中,有個 allowSyntheticDefaultImports 選項,就是針對這種語法作兼容。

若是設定 allowSyntheticDefaultImportstrue,則檢測導入的模塊是不是 ES6 模塊,若是不是,則查找模塊中是否有 exports.default 導出。

從而達到針對 exports.default 的兼容。

clipboard.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('https://tasaid.com') 
}

foo.d.ts 類型聲明文件源碼:

declare function foo(): void;
export = foo

bar.ts 引用:

import foo = require('./foo')

foo()

clipboard.png

我在 《[JavaScript 和 TypeScript 交叉口 —— 類型定義文件(*.d.ts)
](https://tasaid.com/blog/20171...》中講述過 TypeScript 類型聲明文件對導入導出的影響。

const xx = require('xx')

當一個模塊沒有類型聲明文件的時候,可使用 commonjs 原始的 require() 方式來導入模塊,這樣會默認該模塊爲 any。

總結

最後咱們總體總結下,在 TypeScript 中,有多種 import 的方式,分別對應了 JavaScript 中不一樣的 export。

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

// 標準 es6 模塊
import xx from 'xx'

// commonjs 模塊,類型聲明爲 export = xx
import xx = require('xx')

// 沒有類型聲明,默認導入 any 類型
const xx = require('xx')

針對 babel 編譯出來的 exports.default 語法,ts 提供了 allowSyntheticDefaultImports 選項能夠支持,只不過我的不太推薦。

我的建議將 default 重命名。

import { default as foo } from 'foo'

關於 TypeScript 中類型聲明文件(*.d.ts) 對 import 和 export 的影響,能夠參考我以前寫的 《[JavaScript 和 TypeScript 交叉口 —— 類型定義文件
](https://tasaid.com/blog/20171...》。

原文首發於個人我的網站:據說 - https://tasaid.com,推薦在個人網站閱讀更多技術文章。

前端開發 QQ 羣:377786580

引用和參考

相關文章
相關標籤/搜索