编译器配置项-compilerOptions
互操作约束相关配置项01
允许合成默认导入- allowSyntheticDefaultImports
当 allowSyntheticDefaultImports
设置为 true
时,可以使用下边的 import
:
import React from "react";
替代:
import * as React from "react";
如果一个模块没有指定默认导出,在下边的示例中,如果 allowSyntheticDefaultImport
没有设置为 true
:
// @filename: utilFunctions.js
const getStringLength = (str) => str.length;
module.exports = {
getStringLength,
};
// @filename: index.ts
import utils from "./utilFunctions";
Module '"/home/runner/work/TypeScript-Website/TypeScript-Website/packages/typescriptlang-org/utilFunctions"' has no default export.
const count = utils.getStringLength("Check JS");
上边的代码抛出一个错误,因为导入的 utilFunctions
文件没有指定默认的导出对象。尽管感觉上应该可以这样写。为了方便起见,如果没有指定默认导出,像 Babel 这样的转译器会自动创建一个默认导出对象默认值,模块转译后有点像以下代码:
// @filename: utilFunctions.js
const getStringLength = (str) => str.length;
const allFunctions = {
getStringLength,
};
module.exports = allFunctions;
module.exports.default = allFunctions;
这个配置选项不会影响TypeScript输出的JavaScript代码,只是为了类型检查。这个选项使 TypeScript 的行为与 Babel 保持一致,输出的额外代码用来指定默认导出,这样更符合人类的使用习惯。
ES模块互操作 - esModuleInterop
默认情况下(esModuleInterop
为false
或者未设置)TypeScript 将 CommonJS
/ AMD
/ UMD
模块视为与 ES6 模块类似。在这样做的过程中,以下假设的两个场景是有缺陷的:
-
像
import * as moment from "moment"
这样的命名空间导入的作用与const moment = require("moment")
相同 -
像
import moment from "moment"
默认导入的作用与const moment = require("moment").default
相同
对应的会导致以下两个问题:
-
ES6 模块规范规定,命名空间导入(
import * as x
)只能是一个对象,由于TypeScript 将其视为与= require("x")
相同,所以 TypeScript 将允许将导入视为函数,并被允许调用。但是根据ES规范,这是无效的。 -
虽然准确符合 ES6 模块规范,但大多数
CommonJS
/AMD
/UMD
的模块并不像 TypeScript 的实现那么严格
启用 esModuleInterop
这两个问题将在TypeScript 转译代码的过程中被解决。第一个改变了编译器中的行为,第二个由两个新的辅助函数修复,它们提供了辅助功能以确保输出的 JavaScript 的兼容性:
import * as fs from "fs";
import _ from "lodash";
fs.readFileSync("file.txt", "utf8");
_.chunk(["a", "b", "c", "d"], 2);
禁用 esModuleInterop
时:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const lodash_1 = require("lodash");
fs.readFileSync("file.txt", "utf8");
lodash_1.default.chunk(["a", "b", "c", "d"], 2);
将 esModuleInterop
设置为 true 时:
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs"));
const lodash_1 = __importDefault(require("lodash"));
fs.readFileSync("file.txt", "utf8");
lodash_1.default.chunk(["a", "b", "c", "d"], 2);
注意:命名空间 import import * as fs from "fs"
仅考虑导入对象所拥有的属性(基本上是在对象上设置的属性,而不是通过原型链设置的属性)。如果导入的模块使用继承属性定义其 API,则需要使用默认导入形式(import fs from "fs"
),或者禁用 esModuleInterop
。
注意:您可以通过启用 importHelpers
使TypeScript输出更简洁的JavaScript代码:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const fs = tslib_1.__importStar(require("fs"));
const lodash_1 = tslib_1.__importDefault(require("lodash"));
fs.readFileSync("file.txt", "utf8");
lodash_1.default.chunk(["a", "b", "c", "d"], 2);
启用 esModuleInterop
还将启用 allowedSyntheticDefaultImports
。
网友评论