typescript中的模塊引用

背景

ts能夠用於node環境和web環境,或者說在es module出來以前,大部分的包都是遵循commonjs的,而這些遵循commonjs的包如今大多還存在與nodejs當中,也是nodejs遲遲尚未全面支持esm的緣由。那麼ts怎麼兼容commonjs和esm包呢?html

若是你不經常使用ts或者是沒有在nodejs中用過ts,那麼看到ts 官方的推薦寫法,必定會傻眼,居然是import和require混用……
文件模塊的導入
clipboard.pngnode

回顧cjs和esm

咱們要理解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

esModuleInterop

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...

https://jkchao.github.io/type...

https://www.typescriptlang.or...

相關文章
相關標籤/搜索