Skip to main content

@babel/plugin-transform-typescript

info

这个插件包含在 @babel/preset-typescript 中

这个插件增加了对 TypeScript 编程语言 使用的类型语法的支持。不过,这个插件并不会增加对传入的 JavaScript 进行类型检查的能力。要做到这一点,你需要安装并设置 TypeScript。

🌐 This plugin adds support for the types syntax used by the TypeScript programming language. However, this plugin does not add the ability to type-check the JavaScript passed to it. For that, you will need to install and set up TypeScript.

注意,虽然 TypeScript 编译器 tsc 积极支持某些 JavaScript 提案,比如可选链 (?.)、空值合并 (??) 和类属性 (this.#x),但这个预设并不包含这些特性,因为它们不是仅在 TypeScript 中可用的类型语法。如果你想转译这些特性,我们建议使用 preset-env 搭配 preset-typescript。

🌐 Note that although the TypeScript compiler tsc actively supports certain JavaScript proposals such as optional chaining (?.), nullish coalescing (??) and class properties (this.#x), this preset does not include these features because they are not the types syntax available in TypeScript only. We recommend using preset-env with preset-typescript if you want to transpile these features.

示例​

🌐 Example

在

const x: number = 0;

出

const x = 0;

安装​

🌐 Installation

npm install --save-dev @babel/plugin-transform-typescript

用法​

🌐 Usage

🌐 With a configuration file (Recommended)

babel.config.json
{
"plugins": ["@babel/plugin-transform-typescript"]
}

通过 CLI​

🌐 Via CLI

Shell
babel --plugins @babel/plugin-transform-typescript script.js

通过 Node API​

🌐 Via Node API

JavaScript
require("@babel/core").transformSync("code", {
plugins: ["@babel/plugin-transform-typescript"],
});

选项​

🌐 Options

allowDeclareFields​

boolean,默认值为 false

已在 v7.7.0 中添加

🌐 Added in v7.7.0

note

这将在 Babel 8 中默认启用

启用时,只有当类型专用的类字段带有 declare 修饰符前缀时,它们才会被移除:

🌐 When enabled, type-only class fields are only removed if they are prefixed with the declare modifier:

JavaScript
class A {
declare foo: string; // Removed
bar: string; // Initialized to undefined
}

allowNamespaces​

boolean,默认值为 true。

历史
版本变更
v7.5.0添加了 allowNamespaces,默认值为 false
v7.13.0默认值为 true

启用 TypeScript 命名空间的编译。

🌐 Enables compilation of TypeScript namespaces.

disallowAmbiguousJSXLike​

boolean,默认值为 false

已添加于:v7.16.0

🌐 Added in: v7.16.0

即使没有启用 JSX 解析,这个选项也禁止使用可能与 JSX 混淆的语法(<X> y 类型断言和 <X>() => {} 类型参数)。它在解析 .mts 和 .mjs 文件时的行为与 tsc 相同。

🌐 Even when JSX parsing is not enabled, this option disallows using syntax that would be ambiguous with JSX (<X> y type assertions and <X>() => {} type arguments). It matches the tsc behavior when parsing .mts and .mjs files.

dts​

boolean,默认值为 false

已添加于:v7.20.0

🌐 Added in: v7.20.0

这个选项将启用在 TypeScript 外部声明上下文中的解析,在这种上下文中某些语法有不同的规则(比如 .d.ts 文件和 declare module 块内)。想了解更多关于外部声明上下文的信息,请查看 官方手册 和 TypeScript 深入浅出。

🌐 This option will enable parsing within a TypeScript ambient context, where certain syntax have different rules (like .d.ts files and inside declare module blocks). Please see Official Handbook and TypeScript Deep Dive for more information about ambient contexts.

isTSX​

boolean,默认值为 false

强制启用 jsx 解析。否则尖括号会被当作 TypeScript 的旧类型断言 var foo = <string>bar;。另外,isTSX: true 需要 allExtensions: true。

jsxPragma​

string,默认值为 React.createElement

替换在编译 JSX 表达式时使用的函数。这样我们就能知道这个导入不是类型导入,不应该被移除。

🌐 Replace the function used when compiling JSX expressions. This is so that we know that the import is not a type import, and should not be removed.

jsxPragmaFrag​

string,默认值为 React.Fragment

替换在编译 JSX 片段表达式时使用的函数。这样我们就知道这个导入不是类型导入,也不应该被移除。

🌐 Replace the function used when compiling JSX fragment expressions. This is so that we know that the import is not a type import, and should not be removed.

onlyRemoveTypeImports​

boolean,默认值为 false

待定默认设置更改

在 Babel 9.0 中,默认值将是 true。

已添加于:v7.9.0

🌐 Added in: v7.9.0

当设置为 true 时,转换只会移除 仅类型导入(TypeScript 3.8 引入)。只有在你使用 TypeScript >= 3.8 时才应该使用这个。

🌐 When set to true, the transform will only remove type-only imports (introduced in TypeScript 3.8). This should only be used if you are using TypeScript >= 3.8.

JavaScript
class A {
declare foo: string; // Removed
bar: string; // Initialized to undefined
prop?: string; // Initialized to undefined
prop1!: string // Initialized to undefined
}

optimizeConstEnums​

boolean,默认值为 false

已添加于:v7.15.0

🌐 Added in: v7.15.0

当设置为 true 时,Babel 会将枚举值内联,而不是使用通常的 enum 输出:

🌐 When set to true, Babel will inline enum values rather than using the usual enum output:

// Input
const enum Animals {
Fish,
}
console.log(Animals.Fish);

// Default output
var Animals;

(function(Animals) {
Animals[(Animals["Fish"] = 0)] = "Fish";
})(Animals || (Animals = {}));

console.log(Animals.Fish);

// `optimizeConstEnums` output
console.log(0);

这个选项与 TypeScript 的 --isolatedModules 行为不同,后者会忽略 const 修饰符并将它们编译为普通枚举,并且使 Babel 的行为与 TypeScript 的默认行为保持一致。

🌐 This option differs from TypeScript's --isolatedModules behavior, which ignores the const modifier and compiles them as normal enums, and aligns Babel's behavior with TypeScript's default behavior.

不过,当 导出 一个 const enum 时,Babel 会将其编译成一个普通的对象字面量,这样在编译时就不需要依赖跨文件分析了:

🌐 However, when exporting a const enum Babel will compile it to a plain object literal so that it doesn't need to rely on cross-file analysis when compiling it:

// Input
export const enum Animals {
Fish,
}

// `optimizeConstEnums` output
export var Animals = {
Fish: 0,
};

TypeScript 编译器选项​

🌐 TypeScript Compiler Options

官方的 TypeScript 编译器有很多 选项 用于配置它如何编译和类型检查。虽然很多选项可能用不到,但有些行为可能很有用,而且在 Babel 中的对应功能可以通过一些配置选项或插件来启用。

🌐 The official TypeScript compiler has many options for configuring how it compiles and type checks. While many don't apply, some behaviors might be useful and their equivalents in Babel can be enabled by some configuration options or plugins.

  • --alwaysStrict 你可以使用 strictMode 解析器选项:

    JavaScript
    module.exports = {
    parserOpts: { strictMode: true },
    };
  • --downlevelIteration 你可以使用 @babel/plugin-transform-for-of 插件。如果你正在使用 @babel/preset-env,for...of 在你的编译目标不支持迭代器时已经通过迭代器进行了转译。

  • --emitDecoratorMetadata 官方的 Babel 包不支持这个选项,因为它是 TypeScript 特有的新增功能,并不是装饰器提案的一部分。如果你依赖这个功能,可以使用社区插件 babel-plugin-transform-typescript-metadata。

  • --esModuleInterop 这是 Babel 在转译 ECMAScript 模块时的默认行为。

  • --experimentalDecorators 此选项用于启用对“传统”装饰器提案的支持。你可以在 Babel 中使用 @babel/plugin-proposal-decorators 插件启用它,但请注意,会有一些小差异。

    JavaScript
    module.exports = {
    plugins: [["@babel/plugin-proposal-decorators", { legacy: true }]],
    };
  • --importHelpers 这是 @babel/plugin-transform-runtime 包的对应版本。

  • ---importsNotUsedAsValues 你可以使用 onlyRemoveTypeImports 选项来重复这种行为。onlyRemoveTypeImports: true 等同于 importsNotUsedAsValues: preserve,而 onlyRemoveTypeImports: false 等同于 importsNotUsedAsValues: remove。importsNotUsedAsValues: error 没有对应的选项。

  • --inlineSourceMap 你可以在你的 babel.config.json 文件中设置 sourceMaps: "inline" 选项。

  • --isolatedModules 这是 Babel 的默认行为,而且不能关闭,因为 Babel 不支持跨文件分析。

  • --jsx 的 JSX 支持是通过另一个插件提供的。如果你希望输出包含 JSX 代码(例如 --jsx preserve),你需要 @babel/plugin-syntax-jsx 插件;如果你想将其转译为标准 JavaScript(例如 --jsx react 或 --jsx react-native),你应该使用 @babel/plugin-transform-react-jsx 插件。

  • --jsxFactory 可以使用 @babel/plugin-transform-react-jsx 包的 pragma 选项 来定制。你还需要设置这个插件的 jsxPragma 选项。

  • --module,-m 如果你在使用打包工具(Webpack 或 Rollup),这个选项会自动设置。如果你在使用 @babel/preset-env,你可以使用 modules 选项;否则你可以加载具体的插件。

    --module 值@babel/preset-env 的 modules单个插件
    Nonefalse/
    CommonJS"commonjs" 或 "cjs"@babel/plugin-transform-modules-commonjs
    AMD"amd"@babel/plugin-transform-modules-amd
    System"systemjs"@babel/plugin-transform-modules-systemjs
    UMD"umd"@babel/plugin-transform-modules-umd
    ES6 或 ES2015false/
  • --outDir 使用 @babel/cli 时,你可以设置 --out-dir 选项。

  • --outFile Babel 不支持将输出文件拼接在一起:你应该使用一个打包工具(比如 Webpack、Rollup 或 Parcel)来做这件事。使用 @babel/cli 时,你可以通过 --out-file 选项 来编译单个文件。

  • --sourceMap 你可以使用顶层的 sourceMaps: true 选项。

  • --target Babel 不支持针对特定版本的语言,但你可以使用 @babel/preset-env 选择你想要支持的引擎。如果你愿意,你也可以为每个 ECMAScript 特性单独启用 插件。

  • --useDefineForClassFields 你可以使用setPublicClassFields假设来复制这种行为。

  • --watch,-w 使用 @babel/cli 时,你可以指定 --watch 选项。

注意事项​

🌐 Caveats

因为 TypeScript 语言的一些特性依赖完整的类型系统才能在运行时进行更改。这部分的注意事项相当长,不过值得注意的是,其中一些特性只存在于旧的 TypeScript 代码库中,而它们在现代 JavaScript 中有对应的实现,你很可能已经在使用了。

🌐 Because there are features of the TypeScript language which rely on the full type-system to be available to make changes at runtime. This section of caveats is quite long, however, it's worth noting that a few of these features are only found in older TypeScript codebases and have modern JavaScript equivalents which you are probably already using.

  1. 由于 Babel 不进行类型检查,因此语法正确但无法通过 TypeScript 类型检查的代码可能会成功转换,并且通常以意想不到或无效的方式进行转换。

  2. 对你的 tsconfig.json 所做的更改不会在 babel 中反映出来。构建过程总是会表现得好像 isolatedModules 被打开了一样,不过有很多 tsconfig.json 选项 可以通过 Babel 原生的方式配置。

  3. 问:为什么 Babel 不允许导出 var 或 let?

    A:TypeScript 编译器会根据变量的值是否被修改动态改变它们的使用方式。最终,这取决于类型模型,并且超出了 Babel 的处理范围。一个尽力而为的实现会把变量在上下文依赖的使用场景中始终转换为使用 Namespace.Value 版本,而不是 Value,以防它在当前文件之外被修改。因此,如果允许 Babel 使用 var 或 let(因为转换还没写好),很有可能在实际使用时会表现得像是个 bug,而不是 const。

公正的命名空间支持​

🌐 Impartial Namespace Support

如果你已有的代码使用了仅 TypeScript 提供的 命名空间 特性,Babel 只支持 TypeScript 命名空间特性的一部分。如果你打算写新的使用命名空间的代码,建议改用 ES2015 的 import/export。虽然是 不会消失,但有现代的替代方案。

🌐 If you have existing code which uses the TypeScript-only namespace features. Babel supports a subset of TypeScript's namespace features. If you are considering writing new code which uses namespace, using the ES2015 import/export is recommended instead. It's not going away, but there are modern alternatives.

  • 仅类型的 namespace 应标记为 declare,随后将被安全移除。

  • 在 namespace 中使用 var 或 let 对变量进行 export 会导致错误:“Babel 不支持导出非常量的命名空间。请改为 const 或 ...”

    变通方法:使用 const。如果需要某种形式的修改,请明确使用具有内部可变性的对象。

  • namespace 不会共享它们的作用域。在 TypeScript 中,可以在不加限定符的情况下引用 namespace 扩展的上下文项目,编译器会自动添加限定符。在 Babel 中,没有类型模型,也无法动态更改引用以匹配父对象的已建立类型。

    考虑这段代码:

    namespace N {
    export const V = 1;
    }
    namespace N {
    export const W = V;
    }

    TypeScript 编译器将其编译为如下内容:

    JavaScript
    var N = {};
    (function(N) {
    N.V = 1;
    })(N);
    (function(N) {
    N.W = N.V;
    })(N);

    而 Babel 会将它转换成这样的东西:

    JavaScript
    var N;
    (function(_N) {
    const V = (_N = 1);
    })(N || (N = {}));
    (function(_N) {
    const W = V;
    })(N || (N = {}));

    由于 Babel 不理解 N 的类型,引用 V 会成为 undefined,从而导致错误。

    解决方法:即使根据 TypeScript 这些值在作用域内,也要明确引用不在同一命名空间定义的值。示例:

    namespace N {
    export const V = 1;
    }
    namespace N {
    export const W = N.V;
    }

    或者:

    namespace N {
    export const V = 1;
    export const W = V;
    }