编译器选项

"compilerOptions"

JavaScript 支持
  1. allowJs,
  2. checkJs and
  3. maxNodeModuleJsDepth
编辑器支持
  1. disableSizeLimit and
  2. plugins
命令行

    根字段

    🌐 Root Fields

    启动时是 TSConfig 中的根选项——这些选项与你的 TypeScript 或 JavaScript 项目的设置方式有关。

    🌐 Starting up are the root options in the TSConfig - these options relate to how your TypeScript or JavaScript project is set up.

    # 文件 - files

    指定要包含在程序中的文件允许列表。如果找不到任何文件,将会发生错误。

    🌐 Specifies an allowlist of files to include in the program. An error occurs if any of the files can’t be found.

    {
    "": [
    "core.ts",
    "sys.ts",
    "types.ts",
    "scanner.ts",
    "parser.ts",
    "utilities.ts",
    "binder.ts",
    "checker.ts",
    "tsc.ts"
    ]
    }

    当你只有少量文件且不需要使用通配符来引用许多文件时,这很有用。如果你需要那样做,请使用include

    🌐 This is useful when you only have a small number of files and don’t need to use a glob to reference many files. If you need that then use include.

    # 扩展 - extends

    extends 的值是一个字符串,包含要继承的另一个配置文件的路径。该路径可能使用 Node.js 风格的解析方式。

    🌐 The value of extends is a string which contains a path to another configuration file to inherit from. The path may use Node.js style resolution.

    首先加载基础文件的配置,然后再由继承的配置文件中的配置覆盖。配置文件中所有的相对路径都将相对于它们所在的配置文件进行解析。

    🌐 The configuration from the base file are loaded first, then overridden by those in the inheriting config file. All relative paths found in the configuration file will be resolved relative to the configuration file they originated in.

    值得注意的是,继承的配置文件中的 filesincludeexclude覆盖 基础配置文件中的相应项,并且配置文件之间不允许出现循环引用。

    🌐 It’s worth noting that files, include, and exclude from the inheriting config file overwrite those from the base config file, and that circularity between configuration files is not allowed.

    目前,唯一一个不继承的顶层属性是 references

    🌐 Currently, the only top-level property that is excluded from inheritance is references.

    示例

    🌐 Example

    configs/base.json:

    tsconfig.json:

    {
    "": "./configs/base",
    "": ["main.ts", "supplemental.ts"]
    }

    tsconfig.nostrictnull.json:

    {
    "": "./tsconfig",
    }
    }

    在配置文件中找到的具有相对路径的属性(未从继承中排除)将相对于它们起源的配置文件进行解析。

    🌐 Properties with relative paths found in the configuration file, which aren’t excluded from inheritance, will be resolved relative to the configuration file they originated in.

    • 默认:

      false

    • 版本:

      2.1

    # 包含 - include

    指定要包含在程序中的文件名或模式数组。这些文件名是相对于包含 tsconfig.json 文件的目录解析的。

    🌐 Specifies an array of filenames or patterns to include in the program. These filenames are resolved relative to the directory containing the tsconfig.json file.

    json
    {
    "include": ["src/**/*", "tests/**/*"]
    }

    将包括:

    🌐 Which would include:

    .
    ├── scripts ⨯
    │ ├── lint.ts ⨯
    │ ├── update_deps.ts ⨯
    │ └── utils.ts ⨯
    ├── src ✓
    │ ├── client ✓
    │ │ ├── index.ts ✓
    │ │ └── utils.ts ✓
    │ ├── server ✓
    │ │ └── index.ts ✓
    ├── tests ✓
    │ ├── app.test.ts ✓
    │ ├── utils.ts ✓
    │ └── tests.d.ts ✓
    ├── package.json
    ├── tsconfig.json
    └── yarn.lock

    includeexclude 支持通配符,用于创建全局匹配模式:

    • * 匹配零个或多个字符(不包括目录分隔符)
    • ? 匹配任意一个字符(不包括目录分隔符)
    • **/ 匹配任意层级的任何目录

    如果模式中的最后一个路径段不包含文件扩展名或通配符字符,则它会被视为一个目录,并且该目录中具有支持的扩展名的文件将被包括在内(例如,默认包括 .ts.tsx.d.ts,如果 allowJs 设置为 true,则还包括 .js.jsx)。

    🌐 If the last path segment in a pattern does not contain a file extension or wildcard character, then it is treated as a directory, and files with supported extensions inside that directory are included (e.g. .ts, .tsx, and .d.ts by default, with .js and .jsx if allowJs is set to true).

    # 排除 - exclude

    指定在解析 include 时应跳过的文件名或模式数组。

    🌐 Specifies an array of filenames or patterns that should be skipped when resolving include.

    重要exclude 会更改由于include设置而包含的文件。
    通过 exclude 指定的文件仍然可能因为代码中的 import 语句、types 包含、/// <reference 指令,或被列在files清单中而成为你的代码库的一部分。

    这并不是一种能够阻止文件被包含到代码库中的机制——它只是改变了include设置所查找到的内容。

    🌐 It is not a mechanism that prevents a file from being included in the codebase - it simply changes what the include setting finds.

    # 参考文献 - references

    项目引用是一种将 TypeScript 程序拆分为更小部分的方法。使用项目引用可以大大提高构建和编辑器交互的速度,强制组件之间的逻辑分离,并以全新和改进的方式组织代码。

    🌐 Project references are a way to structure your TypeScript programs into smaller pieces. Using Project References can greatly improve build and editor interaction times, enforce logical separation between components, and organize your code in new and improved ways.

    你可以在手册的 项目引用 部分了解更多关于引用如何工作的内容

    🌐 You can read more about how references works in the Project References section of the handbook

    • 默认:

      false

    • 版本:

      3.0

    编译器选项

    🌐 Compiler Options

    这些选项构成了 TypeScript 配置的大部分,它涵盖了语言的工作方式。

    🌐 These options make up the bulk of TypeScript’s configuration and it covers how the language should work.

    #类型检查

    # 允许不可到达的代码 - allowUnreachableCode

    当:

    🌐 When:

    • undefined(默认)向编辑提供警告性建议
    • true 不可达的代码将被忽略
    • false 会引发关于不可达代码的编译器错误

    这些警告仅与由于使用 JavaScript 语法而无法访问的代码有关,例如:

    🌐 These warnings are only about code which is provably unreachable due to the use of JavaScript syntax, for example:

    ts
    function fn(n: number) {
    if (n > 5) {
    return true;
    } else {
    return false;
    }
    return true;
    }

    使用 "allowUnreachableCode": false

    🌐 With "allowUnreachableCode": false:

    ts
    function fn(n: number) {
    if (n > 5) {
    return true;
    } else {
    return false;
    }
    return true;
    Unreachable code detected.7027Unreachable code detected.
    }
    Try

    这不会影响基于类型分析而看起来无法到达的代码的错误。

    🌐 This does not affect errors on the basis of code which appears to be unreachable due to type analysis.

    # 允许未使用的标签 - allowUnusedLabels

    当:

    🌐 When:

    • undefined(默认)向编辑提供警告性建议
    • true 未使用的标签将被忽略
    • false 会引发关于未使用标签的编译器错误

    标签在 JavaScript 中非常罕见,通常表示尝试编写对象字面量:

    🌐 Labels are very rare in JavaScript and typically indicate an attempt to write an object literal:

    ts
    function verifyAge(age: number) {
    // Forgot 'return' statement
    if (age > 18) {
    verified: true;
    Unused label.7028Unused label.
    }
    }
    Try

    # 始终严格 - alwaysStrict

    确保你的文件在 ECMAScript 严格模式下被解析,并为每个源文件输出 “use strict”。

    🌐 Ensures that your files are parsed in the ECMAScript strict mode, and emit “use strict” for each source file.

    ES5 引入了 ECMAScript 严格模式,它通过对 JavaScript 引擎的运行时行为进行调整来提高性能,并且将一系列错误改为抛出而不是静默忽略。

    # 精确可选属性类型 - exactOptionalPropertyTypes

    启用 exactOptionalPropertyTypes 时,TypeScript 对具有 ? 前缀的 typeinterfaces 属性的处理会应用更严格的规则。

    🌐 With exactOptionalPropertyTypes enabled, TypeScript applies stricter rules around how it handles properties on type or interfaces which have a ? prefix.

    例如,这个接口声明有一个属性,该属性可以是两个字符串之一:“dark”或“light”,或者该属性不应存在于对象中。

    🌐 For example, this interface declares that there is a property which can be one of two strings: ‘dark’ or ‘light’ or it should not be in the object.

    ts
    interface UserDefaults {
    // The absence of a value represents 'system'
    colorThemeOverride?: "dark" | "light";
    }

    如果未启用此标志,你可以将 colorThemeOverride 设置为三个值之一:“dark”、“light” 和 undefined

    🌐 Without this flag enabled, there are three values which you can set colorThemeOverride to be: “dark”, “light” and undefined.

    将值设置为 undefined 将使大多数 JavaScript 运行时对存在性的检查失败,这实际上是假的。然而,这并不完全准确;colorThemeOverride: undefined 不等同于 colorThemeOverride 未被定义。例如,"colorThemeOverride" in settings 使用 undefined 作为键时的行为与未定义时将不同。

    🌐 Setting the value to undefined will allow most JavaScript runtime checks for the existence to fail, which is effectively falsy. However, this isn’t quite accurate; colorThemeOverride: undefined is not the same as colorThemeOverride not being defined. For example, "colorThemeOverride" in settings would have different behavior with undefined as the key compared to not being defined.

    exactOptionalPropertyTypes 让 TypeScript 真正强制执行作为可选属性提供的定义:

    ts
    const settings = getUserSettings();
    settings.colorThemeOverride = "dark";
    settings.colorThemeOverride = "light";
     
    // But not:
    settings.colorThemeOverride = undefined;
    Type 'undefined' is not assignable to type '"dark" | "light"' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.2412Type 'undefined' is not assignable to type '"dark" | "light"' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.
    Try
    • 推荐
    • 版本:

      4.4

    # Switch 中没有贯穿的情况 - noFallthroughCasesInSwitch

    报告 switch 语句中存在的贯穿(fallthrough)错误。确保 switch 语句中的任何非空 case 都包含 breakreturnthrow。这意味着你不会意外发布 case 贯穿错误。

    🌐 Report errors for fallthrough cases in switch statements. Ensures that any non-empty case inside a switch statement includes either break, return, or throw. This means you won’t accidentally ship a case fallthrough bug.

    ts
    const a: number = 6;
     
    switch (a) {
    case 0:
    Fallthrough case in switch.7029Fallthrough case in switch.
    console.log("even");
    case 1:
    console.log("odd");
    break;
    }
    Try

    # 禁止隐式 any 类型 - noImplicitAny

    在某些没有类型注解的情况下,当 TypeScript 无法推断变量类型时,会将变量的类型回退为 any

    🌐 In some cases where no type annotations are present, TypeScript will fall back to a type of any for a variable when it cannot infer the type.

    这可能会导致一些错误被遗漏,例如:

    🌐 This can cause some errors to be missed, for example:

    ts
    function fn(s) {
    // No error?
    console.log(s.subtr(3));
    }
    fn(42);
    Try

    然而,开启 noImplicitAny 时,每当 TypeScript 本来会推断 any 时都会报错:

    🌐 Turning on noImplicitAny however TypeScript will issue an error whenever it would have inferred any:

    ts
    function fn(s) {
    Parameter 's' implicitly has an 'any' type.7006Parameter 's' implicitly has an 'any' type.
    console.log(s.subtr(3));
    }
    Try

    # 无隐式覆盖 - noImplicitOverride

    在使用继承的类时,当基类中的函数被重命名时,子类可能会与它重载的函数“不同步”。

    🌐 When working with classes which use inheritance, it’s possible for a sub-class to get “out of sync” with the functions it overloads when they are renamed in the base class.

    例如,假设你正在建模音乐专辑同步系统:

    🌐 For example, imagine you are modeling a music album syncing system:

    ts
    class Album {
    download() {
    // Default behavior
    }
    }
     
    class SharedAlbum extends Album {
    download() {
    // Override to get info from many sources
    }
    }
    Try

    然后,当你添加对机器学习生成的播放列表的支持时,你将 Album 类重构为拥有一个“setup”函数,如下所示:

    🌐 Then when you add support for machine-learning generated playlists, you refactor the Album class to have a ‘setup’ function instead:

    ts
    class Album {
    setup() {
    // Default behavior
    }
    }
     
    class MLAlbum extends Album {
    setup() {
    // Override to get info from algorithm
    }
    }
     
    class SharedAlbum extends Album {
    download() {
    // Override to get info from many sources
    }
    }
    Try

    在这种情况下,TypeScript 并没有发出任何警告,说明 SharedAlbum 上的 download 预期 要重写基类中的一个函数。

    🌐 In this case, TypeScript has provided no warning that download on SharedAlbum expected to override a function in the base class.

    使用 noImplicitOverride,你可以确保子类永远不会不同步,通过确保重写的函数包含关键字 override

    🌐 Using noImplicitOverride you can ensure that the sub-classes never go out of sync, by ensuring that functions which override include the keyword override.

    以下示例启用了 noImplicitOverride,当缺少 override 时,你可以看到收到的错误:

    🌐 The following example has noImplicitOverride enabled, and you can see the error received when override is missing:

    ts
    class Album {
    setup() {}
    }
     
    class MLAlbum extends Album {
    override setup() {}
    }
     
    class SharedAlbum extends Album {
    setup() {}
    This member must have an 'override' modifier because it overrides a member in the base class 'Album'.4114This member must have an 'override' modifier because it overrides a member in the base class 'Album'.
    }
    Try

    # 不允许隐式返回 - noImplicitReturns

    启用后,TypeScript 将检查函数中的所有代码路径以确保它们返回值。

    🌐 When enabled, TypeScript will check all code paths in a function to ensure they return a value.

    ts
    function lookupHeadphonesManufacturer(color: "blue" | "black"): string {
    Function lacks ending return statement and return type does not include 'undefined'.2366Function lacks ending return statement and return type does not include 'undefined'.
    if (color === "blue") {
    return "beats";
    } else {
    ("bose");
    }
    }
    Try

    # 没有隐式的 this - noImplicitThis

    对类型隐含为 ‘any’ 的 ‘this’ 表达式引发错误。

    🌐 Raise error on ‘this’ expressions with an implied ‘any’ type.

    例如,下面的类返回一个函数,该函数尝试访问 this.widththis.height – 但是在 getAreaFunction 内部的函数中,this 的上下文不是 Rectangle 的实例。

    🌐 For example, the class below returns a function which tries to access this.width and this.height – but the context for this inside the function inside getAreaFunction is not the instance of the Rectangle.

    ts
    class Rectangle {
    width: number;
    height: number;
     
    constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
    }
     
    getAreaFunction() {
    return function () {
    return this.width * this.height;
    'this' implicitly has type 'any' because it does not have a type annotation.
    'this' implicitly has type 'any' because it does not have a type annotation.
    2683
    2683
    'this' implicitly has type 'any' because it does not have a type annotation.
    'this' implicitly has type 'any' because it does not have a type annotation.
    };
    }
    }
    Try

    # 无法通过索引签名访问属性 - noPropertyAccessFromIndexSignature

    此设置确保通过“点”(obj.key)语法和“索引”(obj["key"])语法访问字段时,与类型中声明属性的方式保持一致。

    🌐 This setting ensures consistency between accessing a field via the “dot” (obj.key) syntax, and “indexed” (obj["key"]) and the way which the property is declared in the type.

    不启用此标志时,TypeScript 将允许你使用点语法访问未定义的字段:

    🌐 Without this flag, TypeScript will allow you to use the dot syntax to access fields which are not defined:

    ts
    interface GameSettings {
    // Known up-front properties
    speed: "fast" | "medium" | "slow";
    quality: "high" | "low";
     
    // Assume anything unknown to the interface
    // is a string.
    [key: string]: string;
    }
     
    const settings = getSettings();
    settings.speed;
    (property) GameSettings.speed: "fast" | "medium" | "slow"
    settings.quality;
    (property) GameSettings.quality: "high" | "low"
     
    // Unknown key accessors are allowed on
    // this object, and are `string`
    settings.username;
    (index) GameSettings[string]: string
    Try

    打开标志将引发错误,因为未知字段使用点语法而不是索引语法。

    🌐 Turning the flag on will raise an error because the unknown field uses dot syntax instead of indexed syntax.

    ts
    const settings = getSettings();
    settings.speed;
    settings.quality;
     
    // This would need to be settings["username"];
    settings.username;
    Property 'username' comes from an index signature, so it must be accessed with ['username'].4111Property 'username' comes from an index signature, so it must be accessed with ['username'].
    (index) GameSettings[string]: string
    Try

    此标志的目的是在你的调用语法中触发信号,表明你有多确定此属性存在。

    🌐 The goal of this flag is to signal intent in your calling syntax about how certain you are this property exists.

    # 不允许未检查的索引访问 - noUncheckedIndexedAccess

    TypeScript 有一种通过索引签名来描述具有未知键但已知值的对象的方法。

    🌐 TypeScript has a way to describe objects which have unknown keys but known values on an object, via index signatures.

    ts
    interface EnvironmentVars {
    NAME: string;
    OS: string;
     
    // Unknown properties are covered by this index signature.
    [propName: string]: string;
    }
     
    declare const env: EnvironmentVars;
     
    // Declared as existing
    const sysName = env.NAME;
    const os = env.OS;
    const os: string
     
    // Not declared, but because of the index
    // signature, then it is considered a string
    const nodeEnv = env.NODE_ENV;
    const nodeEnv: string
    Try

    开启 noUncheckedIndexedAccess 将会向类型中任何未声明的字段添加 undefined

    🌐 Turning on noUncheckedIndexedAccess will add undefined to any un-declared field in the type.

    ts
    declare const env: EnvironmentVars;
     
    // Declared as existing
    const sysName = env.NAME;
    const os = env.OS;
    const os: string
     
    // Not declared, but because of the index
    // signature, then it is considered a string
    const nodeEnv = env.NODE_ENV;
    const nodeEnv: string | undefined
    Try

    # 没有未使用的本地变量 - noUnusedLocals

    报告未使用的局部变量的错误。

    🌐 Report errors on unused local variables.

    ts
    const createKeyboard = (modelID: number) => {
    const defaultModelID = 23;
    'defaultModelID' is declared but its value is never read.6133'defaultModelID' is declared but its value is never read.
    return { type: "keyboard", modelID };
    };
    Try

    # 没有未使用的参数 - noUnusedParameters

    报告函数中未使用的参数的错误。

    🌐 Report errors on unused parameters in functions.

    ts
    const createDefaultKeyboard = (modelID: number) => {
    'modelID' is declared but its value is never read.6133'modelID' is declared but its value is never read.
    const defaultModelID = 23;
    return { type: "keyboard", modelID: defaultModelID };
    };
    Try

    以下划线开头的参数声明(_)可以免于未使用参数的检查。例如:

    🌐 Parameters declaration with names starting with an underscore (_) are exempt from the unused parameter checking. e.g.:

    ts
    const createDefaultKeyboard = (_modelID: number) => {
    return { type: "keyboard" };
    };
    Try

    # 严格 - strict

    strict 标志启用广泛的类型检查行为,从而提供对程序正确性的更强保证。开启此选项相当于启用下文所述的所有严格模式系列选项。然后,你可以根据需要关闭单个严格模式系列检查。

    🌐 The strict flag enables a wide range of type checking behavior that results in stronger guarantees of program correctness. Turning this on is equivalent to enabling all of the strict mode family options, which are outlined below. You can then turn off individual strict mode family checks as needed.

    TypeScript 的未来版本可能会在此标志下引入更严格的检查,因此升级 TypeScript 可能会导致程序中出现新的类型错误。在适当且可能的情况下,将添加相应的标志以禁用该行为。

    🌐 Future versions of TypeScript may introduce additional stricter checking under this flag, so upgrades of TypeScript might result in new type errors in your program. When appropriate and possible, a corresponding flag will be added to disable that behavior.

    # 严格绑定 调用 应用 - strictBindCallApply

    设置后,TypeScript 将检查函数 callbindapply 的内置方法是否以底层函数的正确参数调用:

    🌐 When set, TypeScript will check that the built-in methods of functions call, bind, and apply are invoked with correct argument for the underlying function:

    ts
    // With strictBindCallApply on
    function fn(x: string) {
    return parseInt(x);
    }
     
    const n1 = fn.call(undefined, "10");
     
    const n2 = fn.call(undefined, false);
    Argument of type 'boolean' is not assignable to parameter of type 'string'.2345Argument of type 'boolean' is not assignable to parameter of type 'string'.
    Try

    否则,这些函数接受任何参数,并将返回 any

    🌐 Otherwise, these functions accept any arguments and will return any:

    ts
    // With strictBindCallApply off
    function fn(x: string) {
    return parseInt(x);
    }
     
    // Note: No error; return type is 'any'
    const n = fn.call(undefined, false);
    Try

    # strictBuiltinIteratorReturn - strictBuiltinIteratorReturn

    内置迭代器实例化时使用的是类型为 TReturn 的 undefined,而不是 any

    🌐 Built-in iterators are instantiated with a TReturn type of undefined instead of any.

    # 严格函数类型 - strictFunctionTypes

    启用后,此标志可更正确地检查函数参数。

    🌐 When enabled, this flag causes functions parameters to be checked more correctly.

    这是一个关闭 strictFunctionTypes 的基本示例:

    🌐 Here’s a basic example with strictFunctionTypes off:

    ts
    function fn(x: string) {
    console.log("Hello, " + x.toLowerCase());
    }
     
    type StringOrNumberFunc = (ns: string | number) => void;
     
    // Unsafe assignment
    let func: StringOrNumberFunc = fn;
    // Unsafe call - will crash
    func(10);
    Try

    strictFunctionTypes 开启 时,错误会被正确检测到:

    🌐 With strictFunctionTypes on, the error is correctly detected:

    ts
    function fn(x: string) {
    console.log("Hello, " + x.toLowerCase());
    }
     
    type StringOrNumberFunc = (ns: string | number) => void;
     
    // Unsafe assignment is prevented
    let func: StringOrNumberFunc = fn;
    Type '(x: string) => void' is not assignable to type 'StringOrNumberFunc'. Types of parameters 'x' and 'ns' are incompatible. Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'.2322Type '(x: string) => void' is not assignable to type 'StringOrNumberFunc'. Types of parameters 'x' and 'ns' are incompatible. Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'.
    Try

    在开发此功能的过程中,我们发现了大量本质上不安全的类层次结构,包括 DOM 中的一些。因此,该设置仅适用于以 function 语法编写的函数,而不适用于以 method 语法编写的函数:

    🌐 During development of this feature, we discovered a large number of inherently unsafe class hierarchies, including some in the DOM. Because of this, the setting only applies to functions written in function syntax, not to those in method syntax:

    ts
    type Methodish = {
    func(x: string | number): void;
    };
     
    function fn(x: string) {
    console.log("Hello, " + x.toLowerCase());
    }
     
    // Ultimately an unsafe assignment, but not detected
    const m: Methodish = {
    func: fn,
    };
    m.func(10);
    Try

    # 严格的空值检查 - strictNullChecks

    strictNullChecksfalse 时,语言会忽略 nullundefined。这可能在运行时导致意外错误。

    🌐 When strictNullChecks is false, null and undefined are effectively ignored by the language. This can lead to unexpected errors at runtime.

    strictNullCheckstrue 时,nullundefined 各自有不同的类型,如果你在需要具体值的地方使用它们,将会出现类型错误。

    🌐 When strictNullChecks is true, null and undefined have their own distinct types and you’ll get a type error if you try to use them where a concrete value is expected.

    例如,对于这段 TypeScript 代码,users.find 并不能保证实际上会找到一个用户,但你可以像它会找到一样编写代码:

    🌐 For example with this TypeScript code, users.find has no guarantee that it will actually find a user, but you can write code as though it will:

    ts
    declare const loggedInUsername: string;
     
    const users = [
    { name: "Oby", age: 12 },
    { name: "Heera", age: 32 },
    ];
     
    const loggedInUser = users.find((u) => u.name === loggedInUsername);
    console.log(loggedInUser.age);
    Try

    strictNullChecks 设置为 true 会引发错误,因为在尝试使用 loggedInUser 之前,你尚未保证它的存在。

    🌐 Setting strictNullChecks to true will raise an error that you have not made a guarantee that the loggedInUser exists before trying to use it.

    ts
    declare const loggedInUsername: string;
     
    const users = [
    { name: "Oby", age: 12 },
    { name: "Heera", age: 32 },
    ];
     
    const loggedInUser = users.find((u) => u.name === loggedInUsername);
    console.log(loggedInUser.age);
    'loggedInUser' is possibly 'undefined'.18048'loggedInUser' is possibly 'undefined'.
    Try

    第二个例子失败了,因为数组的 find 函数看起来有点像这种简化:

    🌐 The second example failed because the array’s find function looks a bit like this simplification:

    ts
    // When strictNullChecks: true
    type Array = {
    find(predicate: (value: any, index: number) => boolean): S | undefined;
    };
    // When strictNullChecks: false the undefined is removed from the type system,
    // allowing you to write code which assumes it always found a result
    type Array = {
    find(predicate: (value: any, index: number) => boolean): S;
    };

    # 严格的属性初始化 - strictPropertyInitialization

    设置为 true 时,如果声明了类属性但未在构造函数中设置,则 TypeScript 会引发错误。

    🌐 When set to true, TypeScript will raise an error when a class property was declared but not set in the constructor.

    ts
    class UserAccount {
    name: string;
    accountType = "user";
     
    email: string;
    Property 'email' has no initializer and is not definitely assigned in the constructor.2564Property 'email' has no initializer and is not definitely assigned in the constructor.
    address: string | undefined;
     
    constructor(name: string) {
    this.name = name;
    // Note that this.email is not set
    }
    }
    Try

    在上述情况下:

    🌐 In the above case:

    • this.name 已被特别设置。
    • this.accountType 为默认设置。
    • this.email 未设置,会导致错误。
    • this.address 被声明为可能是 undefined,这意味着它不必被设置。

    # 在捕获变量中使用 Unknown - useUnknownInCatchVariables

    在 TypeScript 4.0 中,新增了支持,可以将 catch 子句中变量的类型从 any 改为 unknown。允许出现如下代码:

    🌐 In TypeScript 4.0, support was added to allow changing the type of the variable in a catch clause from any to unknown. Allowing for code like:

    ts
    try {
    // ...
    } catch (err: unknown) {
    // We have to verify err is an
    // error before using it as one.
    if (err instanceof Error) {
    console.log(err.message);
    }
    }
    Try

    这种模式确保了错误处理代码更加全面,因为你不能提前保证被抛出的对象一定是 Error 子类。启用 useUnknownInCatchVariables 标志后,你就不需要额外的语法(: unknown)或 linter 规则来尝试强制执行这种行为。

    🌐 This pattern ensures that error handling code becomes more comprehensive because you cannot guarantee that the object being thrown is a Error subclass ahead of time. With the flag useUnknownInCatchVariables enabled, then you do not need the additional syntax (: unknown) nor a linter rule to try enforce this behavior.

    #模块

    # 允许任意扩展 - allowArbitraryExtensions

    在 TypeScript 5.0 中,当导入路径以不是已知 JavaScript 或 TypeScript 文件扩展名的扩展名结尾时,编译器会查找该路径对应的声明文件,格式为 {file basename}.d.{extension}.ts。 例如,如果你在打包项目中使用 CSS 加载器,你可能希望为那些样式表编写(或生成)声明文件:

    🌐 In TypeScript 5.0, when an import path ends in an extension that isn’t a known JavaScript or TypeScript file extension, the compiler will look for a declaration file for that path in the form of {file basename}.d.{extension}.ts. For example, if you are using a CSS loader in a bundler project, you might want to write (or generate) declaration files for those stylesheets:

    css
    /* app.css */
    .cookie-banner {
    display: none;
    }
    ts
    // app.d.css.ts
    declare const css: {
    cookieBanner: string;
    };
    export default css;
    ts
    // App.tsx
    import styles from "./app.css";
    styles.cookieBanner; // string

    默认情况下,这个导入会抛出一个错误,提示你 TypeScript 不理解这种文件类型,并且你的运行时可能不支持导入它。但是,如果你已经配置了运行时或打包工具来处理它,你可以使用新的 --allowArbitraryExtensions 编译器选项来抑制错误。

    🌐 By default, this import will raise an error to let you know that TypeScript doesn’t understand this file type and your runtime might not support importing it. But if you’ve configured your runtime or bundler to handle it, you can suppress the error with the new --allowArbitraryExtensions compiler option.

    请注意,从历史上看,通过添加名为 app.css.d.ts 的声明文件而不是 app.d.css.ts,通常可以实现类似的效果——然而,这只是通过 Node 对 CommonJS 的 require 解析规则实现的。严格来说,前者被解释为一个名为 app.css.js 的 JavaScript 文件的声明文件。由于在 Node 的 ESM 支持中,相对文件导入需要包含扩展名,因此在 --moduleResolution node16nodenext 下的 ESM 文件中,我们的示例会在 TypeScript 中报错。

    🌐 Note that historically, a similar effect has often been achievable by adding a declaration file named app.css.d.ts instead of app.d.css.ts - however, this just worked through Node’s require resolution rules for CommonJS. Strictly speaking, the former is interpreted as a declaration file for a JavaScript file named app.css.js. Because relative files imports need to include extensions in Node’s ESM support, TypeScript would error on our example in an ESM file under --moduleResolution node16 or nodenext.

    欲了解更多信息,请阅读此功能的提案以及其对应的拉取请求

    🌐 For more information, read up the proposal for this feature and its corresponding pull request.

    # 允许导入 TS 扩展 - allowImportingTsExtensions

    --allowImportingTsExtensions 允许 TypeScript 文件使用 TypeScript 特有的扩展名(如 .ts.mts.tsx)相互导入。

    只有在启用 --noEmit--emitDeclarationOnly 时才允许使用此标志,因为在 JavaScript 输出文件中这些导入路径在运行时无法解析。这里的期望是你的解析器(例如你的打包工具、运行时或其他工具)能够使 .ts 文件之间的这些导入正常工作。

    🌐 This flag is only allowed when --noEmit or --emitDeclarationOnly is enabled, since these import paths would not be resolvable at runtime in JavaScript output files. The expectation here is that your resolver (e.g. your bundler, a runtime, or some other tool) is going to make these imports between .ts files work.

    # 允许 Umd 全局访问 - allowUmdGlobalAccess

    当设置为 true 时,allowUmdGlobalAccess 允许你在模块文件内部将 UMD 导出作为全局变量访问。模块文件是包含导入和/或导出的文件。如果没有这个标志,使用 UMD 模块的导出需要一个导入声明。

    🌐 When set to true, allowUmdGlobalAccess lets you access UMD exports as globals from inside module files. A module file is a file that has imports and/or exports. Without this flag, using an export from a UMD module requires an import declaration.

    此标志的一个示例用例是一个 Web 项目,你知道特定的库(如 jQuery 或 Lodash)在运行时始终可用,但你无法通过导入访问它。

    🌐 An example use case for this flag would be a web project where you know the particular library (like jQuery or Lodash) will always be available at runtime, but you can’t access it with an import.

    # 基本 URL - baseUrl

    设置一个基础目录,用于解析裸模块名。例如,在目录结构中:

    🌐 Sets a base directory from which to resolve bare specifier module names. For example, in the directory structure:

    project
    ├── ex.ts
    ├── hello
    │ └── world.ts
    └── tsconfig.json

    使用 "baseUrl": "./" 时,TypeScript 会从与 tsconfig.json 相同的文件夹开始查找文件:

    🌐 With "baseUrl": "./", TypeScript will look for files starting at the same folder as the tsconfig.json:

    ts
    import { helloWorld } from "hello/world";
    console.log(helloWorld);

    该解析优先于来自 node_modules 的查找。

    🌐 This resolution has higher priority than lookups from node_modules.

    此功能旨在与浏览器中的 AMD 模块加载器配合使用,并不推荐在其他情况下使用。从 TypeScript 4.1 开始,使用 paths 时不再需要设置 baseUrl

    🌐 This feature was designed for use in conjunction with AMD module loaders in the browser, and is not recommended in any other context. As of TypeScript 4.1, baseUrl is no longer required to be set when using paths.

    # 自定义条件 - customConditions

    --customConditions 接受一个额外 条件 列表,当 TypeScript 从 package.jsonexportsimports 字段解析时,这些条件应该成功。这些条件会被添加到解析器默认使用的任何现有条件中。

    例如,当在 tsconfig.json 中如此设置此字段时:

    🌐 For example, when this field is set in a tsconfig.json as so:

    jsonc
    {
    "compilerOptions": {
    "target": "es2022",
    "moduleResolution": "bundler",
    "customConditions": ["my-condition"]
    }
    }

    每当在 package.json 中引用 exportsimports 字段时,TypeScript 会考虑称为 my-condition 的条件。

    🌐 Any time an exports or imports field is referenced in package.json, TypeScript will consider conditions called my-condition.

    所以当从包含以下 package.json 的包导入时

    🌐 So when importing from a package with the following package.json

    jsonc
    {
    // ...
    "exports": {
    ".": {
    "my-condition": "./foo.mjs",
    "node": "./bar.mjs",
    "import": "./baz.mjs",
    "require": "./biz.mjs"
    }
    }
    }

    TypeScript 会尝试查找与 foo.mjs 对应的文件。

    🌐 TypeScript will try to look for files corresponding to foo.mjs.

    此字段仅在 --moduleResolutionnode16nodenextbundler 选项下有效。

    🌐 This field is only valid under the node16, nodenext, and bundler options for --moduleResolution.

    # 模块 - module

    为程序设置模块系统。有关更多信息,请参阅 TypeScript module 选项的理论参考页面。对于现代 Node.js 项目,你很可能需要使用 "nodenext",而对于将要打包的代码,则需要使用 preserveesnext

    🌐 Sets the module system for the program. See the theory behind TypeScript’s module option and its reference page for more information. You very likely want "nodenext" for modern Node.js projects and preserve or esnext for code that will be bundled.

    更改 module 会影响 moduleResolution,其 也有一个参考页面

    🌐 Changing module affects moduleResolution which also has a reference page.

    这是此文件的一些示例输出:

    🌐 Here’s some example output for this file:

    ts
    // @filename: index.ts
    import { valueOfPi } from "./constants";
     
    export const twoPi = valueOfPi * 2;
    Try

    CommonJS

    ts
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.twoPi = void 0;
    const constants_1 = require("./constants");
    exports.twoPi = constants_1.valueOfPi * 2;
     
    Try

    UMD

    ts
    (function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
    var v = factory(require, exports);
    if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
    define(["require", "exports", "./constants"], factory);
    }
    })(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.twoPi = void 0;
    const constants_1 = require("./constants");
    exports.twoPi = constants_1.valueOfPi * 2;
    });
     
    Try

    AMD

    ts
    define(["require", "exports", "./constants"], function (require, exports, constants_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.twoPi = void 0;
    exports.twoPi = constants_1.valueOfPi * 2;
    });
     
    Try

    System

    ts
    System.register(["./constants"], function (exports_1, context_1) {
    "use strict";
    var constants_1, twoPi;
    var __moduleName = context_1 && context_1.id;
    return {
    setters: [
    function (constants_1_1) {
    constants_1 = constants_1_1;
    }
    ],
    execute: function () {
    exports_1("twoPi", twoPi = constants_1.valueOfPi * 2);
    }
    };
    });
     
    Try

    ESNext

    ts
    import { valueOfPi } from "./constants";
    export const twoPi = valueOfPi * 2;
     
    Try

    ES2015/ES6/ES2020/ES2022

    ts
    import { valueOfPi } from "./constants";
    export const twoPi = valueOfPi * 2;
     
    Try

    除了 ES2015/ES6 的基本功能之外,ES2020 还增加了对 动态 importimport.meta 的支持,而 ES2022 进一步增加了对 顶层 await 的支持。

    🌐 In addition to the base functionality of ES2015/ES6, ES2020 adds support for dynamic imports, and import.meta while ES2022 further adds support for top level await.

    node16/node18/node20/nodenext

    node16node18node20nodenext 模式与 Node 的 原生 ECMAScript 模块支持 集成。生成的 JavaScript 会根据文件扩展名以及最近的 package.jsontype 设置的值使用 CommonJSES2020 输出。模块解析也有所不同。你可以在 手册模块参考 中了解更多信息。

    🌐 The node16, node18, node20, and nodenext modes integrate with Node’s native ECMAScript Module support. The emitted JavaScript uses either CommonJS or ES2020 output depending on the file extension and the value of the type setting in the nearest package.json. Module resolution also works differently. You can learn more in the handbook and Modules Reference.

    • node16 从 TypeScript 4.7 开始可用
    • node18 从 TypeScript 5.8 开始可用,用来替代 node16,并增加了对导入属性的支持。
    • node20 增加了对 require(ESM) 的支持。
    • nodenext 从 TypeScript 4.7 开始可用,但在最新稳定版本的 Node.js 中其行为有所变化。--module nodenext 意味着浮动的 --target esnext

    preserve

    --module preserve(在 TypeScript 5.4 中新增)中,输入文件中编写的 ECMAScript 导入和导出会在输出中保留,而 CommonJS 风格的 import x = require("...")export = ... 语句会作为 CommonJS 的 requiremodule.exports 输出。换句话说,每个单独的导入或导出语句的格式都会被保留,而不会被强制转换为整个编译(甚至整个文件)的单一格式。

    🌐 In --module preserve (added in TypeScript 5.4), ECMAScript imports and exports written in input files are preserved in the output, and CommonJS-style import x = require("...") and export = ... statements are emitted as CommonJS require and module.exports. In other words, the format of each individual import or export statement is preserved, rather than being coerced into a single format for the whole compilation (or even a whole file).

    ts
    import { valueOfPi } from "./constants";
    const constants = require("./constants");
    export const piSquared = valueOfPi * constants.valueOfPi;
     
    Try

    虽然在同一个文件中同时使用 import 和 require 调用的情况很少,但这种 module 模式最能反映大多数现代打包工具以及 Bun 运行时的功能。

    🌐 While it’s rare to need to mix imports and require calls in the same file, this module mode best reflects the capabilities of most modern bundlers, as well as the Bun runtime.

    为什么要关心 TypeScript 在使用打包工具或 Bun 时的 module 输出,尤其你可能还设置了 noEmit?TypeScript 的类型检查和模块解析行为会受到其 将要 输出的模块格式的影响。设置 module 可以向 TypeScript 提供信息,让它了解你的打包工具或运行时如何处理导入和导出,从而确保你在导入的值上看到的类型准确地反映了在运行时或打包后实际发生的情况。

    None

    ts
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.twoPi = void 0;
    const constants_1 = require("./constants");
    exports.twoPi = constants_1.valueOfPi * 2;
     
    Try

    # 模块解析 - moduleResolution

    指定模块解析策略:

    🌐 Specify the module resolution strategy:

    • 'node16''nodenext' 适用于现代版本的 Node.js。Node.js v12 及更高版本同时支持 ECMAScript 导入和 CommonJS require,它们使用不同的算法进行解析。这些 moduleResolution 值与相应的 module 值结合时,会根据输出的 JavaScript 代码中 Node.js 是否会看到 importrequire 来选择每个解析所使用的正确算法。
    • 'node10'(之前称为 'node')适用于早于 v10 的 Node.js 版本,这些版本仅支持 CommonJS require。在现代代码中,你可能不需要使用 node10
    • 'bundler' 用于与打包工具一起使用。像 node16nodenext 一样,这种模式支持 package.json 中的 "imports""exports",但与 Node.js 的解析模式不同,bundler 在导入相对路径时从不要求文件扩展名。
    • 'classic' 在 TypeScript 1.6 发布之前被使用过。classic 不应该被使用。

    有参考页面解释了 TypeScript 模块解析背后的理论每个选项的详细信息

    🌐 There are reference pages explaining the theory behind TypeScript’s module resolution and the details of each option.

    # 模块后缀 - moduleSuffixes

    提供一种方法来覆盖解析模块时要搜索的默认文件名后缀列表。

    🌐 Provides a way to override the default list of file name suffixes to search when resolving a module.

    {
    "": [".ios", ".native", ""]
    }
    }

    给定上述配置,导入如下:

    🌐 Given the above configuration, an import like the following:

    ts
    import * as foo from "./foo";

    TypeScript 将会查找相对文件 ./foo.ios.ts./foo.native.ts,最后是 ./foo.ts

    🌐 TypeScript will look for the relative files ./foo.ios.ts, ./foo.native.ts, and finally ./foo.ts.

    注意 moduleSuffixes 中的空字符串 "",这是 TypeScript 查找 ./foo.ts 所必需的。

    🌐 Note the empty string "" in moduleSuffixes which is necessary for TypeScript to also look-up ./foo.ts.

    此功能对于 React Native 项目非常有用,因为每个目标平台都可以使用不同 moduleSuffixes 的独立 tsconfig.json。

    🌐 This feature can be useful for React Native projects where each target platform can use a separate tsconfig.json with differing moduleSuffixes.

    # 无解决方案 - noResolve

    默认情况下,TypeScript 会检查初始文件集中用于 import<reference 的指令,并将这些已解析的文件添加到你的程序中。

    🌐 By default, TypeScript will examine the initial set of files for import and <reference directives and add these resolved files to your program.

    如果设置了 noResolve,这个过程就不会发生。然而,仍然会检查 import 语句以确定它们是否解析为有效模块,因此你需要通过其他方式确保这一点。

    🌐 If noResolve is set, this process doesn’t happen. However, import statements are still checked to see if they resolve to a valid module, so you’ll need to make sure this is satisfied by some other means.

    # noUncheckedSideEffectImports - noUncheckedSideEffectImports

    在 JavaScript 中,可以在不实际从模块中导入任何值的情况下 import 一个模块。

    🌐 In JavaScript it’s possible to import a module without actually importing any values from it.

    ts
    import "some-module";

    这些导入通常被称为副作用导入,因为它们唯一有用的行为就是执行某些副作用(比如注册全局变量,或者向原型添加一个 polyfill)。

    🌐 These imports are often called side effect imports because the only useful behavior they can provide is by executing some side effect (like registering a global variable, or adding a polyfill to a prototype).

    默认情况下,TypeScript 不会检查这些导入是否有效。如果导入解析到有效的源文件,TypeScript 将加载并检查该文件。如果未找到源文件,TypeScript 将静默地忽略该导入。

    🌐 By default, TypeScript will not check these imports for validity. If the import resolves to a valid source file, TypeScript will load and check the file. If no source file is found, TypeScript will silently ignore the import.

    这是令人惊讶的行为,但它部分源于 JavaScript 生态系统中的建模模式。例如,这种语法也曾在打包工具中与特殊加载器一起使用,以加载 CSS 或其他资源。你的打包工具可能被配置成可以通过如下方式包含特定的 .css 文件:

    🌐 This is surprising behavior, but it partially stems from modeling patterns in the JavaScript ecosystem. For example, this syntax has also been used with special loaders in bundlers to load CSS or other assets. Your bundler might be configured in such a way where you can include specific .css files by writing something like the following:

    tsx
    import "./button-component.css";
    export function Button() {
    // ...
    }

    不过,这掩盖了副作用导入中的潜在拼写错误。

    🌐 Still, this masks potential typos on side effect imports.

    当启用 --noUncheckedSideEffectImports 时,如果 TypeScript 找不到副作用导入的源文件,将会报错。

    🌐 When --noUncheckedSideEffectImports is enabled, TypeScript will error if it can’t find a source file for a side effect import.

    ts
    import "oops-this-module-does-not-exist";
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // error: Cannot find module 'oops-this-module-does-not-exist' or its corresponding
    // type declarations.

    启用此选项时,一些原本可用的代码可能会出现错误,就像上面的 CSS 示例一样。 为了解决这个问题,那些只想为资源编写副作用 import 的用户可能更适合编写所谓的带有通配符指定符的环境模块声明。 它将放在全局文件中,看起来大致如下:

    🌐 When enabling this option, some working code may now receive an error, like in the CSS example above. To work around this, users who want to just write side effect imports for assets might be better served by writing what’s called an ambient module declaration with a wildcard specifier. It would go in a global file and look something like the following:

    ts
    // ./src/globals.d.ts
    // Recognize all CSS files as module imports.
    declare module "*.css" {}

    事实上,你的项目中可能已经有这样的文件了! 例如,运行类似 vite init 的命令可能会创建一个类似的 vite-env.d.ts

    🌐 In fact, you might already have a file like this in your project! For example, running something like vite init might create a similar vite-env.d.ts.

    # 路径 - paths

    一系列条目,将导入重新映射到相对于 baseUrl 的查找位置(如果已设置),否则相对于 tsconfig 文件本身。有关 paths 的更全面说明,请参阅 moduleResolution 参考页

    🌐 A series of entries which re-map imports to lookup locations relative to the baseUrl if set, or to the tsconfig file itself otherwise. There is a larger coverage of paths in the moduleResolution reference page.

    paths 允许你声明 TypeScript 应该如何在你的 require/import 中解析导入。

    {
    "": {
    "jquery": ["./vendor/jquery/dist/jquery"]
    }
    }
    }

    这将允许你可以编写 import "jquery",并在本地获得所有正确的类型提示。

    🌐 This would allow you to be able to write import "jquery", and get all of the correct typing locally.

    {
    "": {
    "app/*": ["./src/app/*"],
    "config/*": ["./src/app/_config/*"],
    "environment/*": ["./src/environments/*"],
    "shared/*": ["./src/app/_shared/*"],
    "helpers/*": ["./src/helpers/*"],
    "tests/*": ["./src/tests/*"]
    }
    }
    }

    在这种情况下,你可以告诉 TypeScript 文件解析器支持多个自定义前缀来查找代码。

    🌐 In this case, you can tell the TypeScript file resolver to support a number of custom prefixes to find code.

    请注意,此功能不会更改 tsc 导出的导入路径,因此 paths 应仅用于告知 TypeScript 另一个工具具有此映射,并将在运行时或打包时使用它。

    🌐 Note that this feature does not change how import paths are emitted by tsc, so paths should only be used to inform TypeScript that another tool has this mapping and will use it at runtime or when bundling.

    # 解析 JSON 模块 - resolveJsonModule

    允许导入扩展名为 .json 的模块,这是在 Node 项目中常见的做法。这包括根据静态 JSON 结构为 import 生成类型。

    🌐 Allows importing modules with a .json extension, which is a common practice in node projects. This includes generating a type for the import based on the static JSON shape.

    TypeScript 默认不支持解析 JSON 文件:

    🌐 TypeScript does not support resolving JSON files by default:

    ts
    // @filename: settings.json
    {
    "repo": "TypeScript",
    "dry": false,
    "debug": false
    }
    // @filename: index.ts
    import settings from "./settings.json";
    Cannot find module './settings.json' or its corresponding type declarations.2307Cannot find module './settings.json' or its corresponding type declarations.
     
    settings.debug === true;
    settings.dry === 2;
    Try

    启用该选项允许导入 JSON,并验证该 JSON 文件中的类型。

    🌐 Enabling the option allows importing JSON, and validating the types in that JSON file.

    ts
    // @filename: settings.json
    {
    "repo": "TypeScript",
    "dry": false,
    "debug": false
    }
    // @filename: index.ts
    import settings from "./settings.json";
     
    settings.debug === true;
    settings.dry === 2;
    This comparison appears to be unintentional because the types 'boolean' and 'number' have no overlap.2367This comparison appears to be unintentional because the types 'boolean' and 'number' have no overlap.
    Try

    # 解决 package.json 导出 - resolvePackageJsonExports

    --resolvePackageJsonExports 会强制 TypeScript 在从 node_modules 中的某个包读取内容时,查阅 package.json 文件的 exports 字段

    --moduleResolutionnode16nodenextbundler 选项下,此选项默认设置为 true

    🌐 This option defaults to true under the node16, nodenext, and bundler options for --moduleResolution.

    # 解析 package.json 导入 - resolvePackageJsonImports

    --resolvePackageJsonImports 强制 TypeScript 在执行从其祖级目录包含 package.json 的文件中以 # 开头的查找时,参考 package.json 文件的 imports 字段

    --moduleResolutionnode16nodenextbundler 选项下,此选项默认设置为 true

    🌐 This option defaults to true under the node16, nodenext, and bundler options for --moduleResolution.

    # rewriteRelativeImportExtensions - rewriteRelativeImportExtensions

    在输出文件中,将相对导入路径中的 .ts.tsx.mts.cts 文件扩展名重写为它们的 JavaScript 等效项。

    🌐 Rewrite .ts, .tsx, .mts, and .cts file extensions in relative import paths to their JavaScript equivalent in output files.

    欲了解更多信息,请参阅 TypeScript 5.7 发布说明

    🌐 For more information, see the TypeScript 5.7 release notes.

    # 根目录 - rootDir

    默认:所有非声明输入文件的最长公共路径。如果设置了 composite,默认值则改为包含 tsconfig.json 文件的目录。

    当 TypeScript 编译文件时,它会在输出目录中保留与输入目录中相同的目录结构。

    🌐 When TypeScript compiles files, it keeps the same directory structure in the output directory as exists in the input directory.

    例如,假设你有一些输入文件:

    🌐 For example, let’s say you have some input files:

    MyProj
    ├── tsconfig.json
    ├── core
    │ ├── a.ts
    │ ├── b.ts
    │ ├── sub
    │ │ ├── c.ts
    ├── types.d.ts

    rootDir 的推断值是所有非声明输入文件的最长公共路径,在本例中为 core/

    🌐 The inferred value for rootDir is the longest common path of all non-declaration input files, which in this case is core/.

    如果你的 outDirdist,TypeScript 会写出这个树状结构:

    🌐 If your outDir was dist, TypeScript would write this tree:

    MyProj
    ├── dist
    │ ├── a.js
    │ ├── b.js
    │ ├── sub
    │ │ ├── c.js

    但是,你可能打算将 core 作为输出目录结构的一部分。通过在 tsconfig.json 中设置 rootDir: ".",TypeScript 将写入如下树结构:

    🌐 However, you may have intended for core to be part of the output directory structure. By setting rootDir: "." in tsconfig.json, TypeScript would write this tree:

    MyProj
    ├── dist
    │ ├── core
    │ │ ├── a.js
    │ │ ├── b.js
    │ │ ├── sub
    │ │ │ ├── c.js

    重要的是,rootDir 不会影响哪些文件成为编译的一部分。 它不会与 includeexcludefilestsconfig.json 设置产生交互。

    🌐 Importantly, rootDir does not affect which files become part of the compilation. It has no interaction with the include, exclude, or files tsconfig.json settings.

    请注意,TypeScript 永远不会将输出文件写入 outDir 之外的目录,也永远不会跳过生成文件。因此,rootDir 还强制要求所有需要生成的文件都必须位于 rootDir 路径下。

    🌐 Note that TypeScript will never write an output file to a directory outside of outDir, and will never skip emitting a file. For this reason, rootDir also enforces that all files which need to be emitted are underneath the rootDir path.

    例如,假设你有这棵树:

    🌐 For example, let’s say you had this tree:

    MyProj
    ├── tsconfig.json
    ├── core
    │ ├── a.ts
    │ ├── b.ts
    ├── helpers.ts

    rootDir 指定为 core 并且将 include 指定为 * 是错误的,因为这样会创建一个文件(helpers.ts),该文件需要在 outDir 之外生成(即 ../helpers.js)。

    🌐 It would be an error to specify rootDir as core and include as * because it creates a file (helpers.ts) that would need to be emitted outside the outDir (i.e. ../helpers.js).

    • 默认:

      Computed from the list of input files.

    • 版本:

      1.5

    # 根目录 - rootDirs

    使用 rootDirs,你可以告知编译器,有许多“虚拟”目录作为单一根目录存在。这允许编译器解析这些“虚拟”目录内的相对模块导入,就好像它们被合并为一个目录一样。

    🌐 Using rootDirs, you can inform the compiler that there are many “virtual” directories acting as a single root. This allows the compiler to resolve relative module imports within these “virtual” directories, as if they were merged in to one directory.

    例如:

    🌐 For example:

    src
    └── views
    └── view1.ts (can import "./template1", "./view2`)
    └── view2.ts (can import "./template1", "./view1`)
    generated
    └── templates
    └── views
    └── template1.ts (can import "./view1", "./view2")
    {
    "": ["src/views", "generated/templates/views"]
    }
    }

    这不会影响 TypeScript 如何生成 JavaScript,它只是模拟假设它们在运行时能够通过这些相对路径工作。

    🌐 This does not affect how TypeScript emits JavaScript, it only emulates the assumption that they will be able to work via those relative paths at runtime.

    rootDirs 可以用于为非 TypeScript 或 JavaScript 的文件提供一个独立的“类型层”,通过在另一个文件夹中为生成的 .d.ts 文件提供存放位置。这种技术对使用 import 的打包应用非常有用,即使这些文件不一定是代码:

    sh
    src
    └── index.ts
    └── css
    └── main.css
    └── navigation.css
    generated
    └── css
    └── main.css.d.ts
    └── navigation.css.d.ts
    {
    "": ["src", "generated"]
    }
    }

    这种技术允许你为非代码源文件预先生成类型。随后,基于源文件的位置,导入就能自然工作。 例如,./src/index.ts 可以导入文件 ./src/css/main.css,而 TypeScript 会通过生成的对应声明文件了解该文件类型的打包器行为。

    🌐 This technique lets you generate types ahead of time for the non-code source files. Imports then work naturally based off the source file’s location. For example ./src/index.ts can import the file ./src/css/main.css and TypeScript will be aware of the bundler’s behavior for that filetype via the corresponding generated declaration file.

    ts
    // @filename: index.ts
    import { appClass } from "./main.css";
    Try
    • 默认:

      Computed from the list of input files.

    • 版本:

      2.0

    # 类型根 - typeRoots

    默认情况下,所有 可见 的“@types”包都会被包含在你的编译中。任何包含文件夹中的 node_modules/@types 包都被视为 可见。例如,这意味着位于 ./node_modules/@types/../node_modules/@types/../../node_modules/@types/ 等文件夹中的包。

    🌐 By default all visible@types” packages are included in your compilation. Packages in node_modules/@types of any enclosing folder are considered visible. For example, that means packages within ./node_modules/@types/, ../node_modules/@types/, ../../node_modules/@types/, and so on.

    如果指定了 typeRoots,将 包含 typeRoots 下的包。例如:

    🌐 If typeRoots is specified, only packages under typeRoots will be included. For example:

    {
    "": ["./typings", "./vendor/types"]
    }
    }

    这个配置文件将包括 ./typings./vendor/types 下的 所有 包,而不包括 ./node_modules/@types 中的任何包。所有路径都是相对于 tsconfig.json 的。

    🌐 This config file will include all packages under ./typings and ./vendor/types, and no packages from ./node_modules/@types. All paths are relative to the tsconfig.json.

    # 类型 - types

    默认情况下,所有 可见 的“@types”包都会被包含在你的编译中。任何包含文件夹中的 node_modules/@types 包都被视为 可见。例如,这意味着位于 ./node_modules/@types/../node_modules/@types/../../node_modules/@types/ 等文件夹中的包。

    🌐 By default all visible@types” packages are included in your compilation. Packages in node_modules/@types of any enclosing folder are considered visible. For example, that means packages within ./node_modules/@types/, ../node_modules/@types/, ../../node_modules/@types/, and so on.

    如果指定了 types,则只有列出的包会包含在全局作用域中。例如:

    🌐 If types is specified, only packages listed will be included in the global scope. For instance:

    {
    "": ["node", "jest", "express"]
    }
    }

    tsconfig.json 文件将 包含 ./node_modules/@types/node./node_modules/@types/jest./node_modules/@types/expressnode_modules/@types/* 下的其他包将不会被包含。

    🌐 This tsconfig.json file will only include ./node_modules/@types/node, ./node_modules/@types/jest and ./node_modules/@types/express. Other packages under node_modules/@types/* will not be included.

    这会产生什么影响?

    🌐 What does this affect?

    此选项不会影响 @types/* 在你的应用代码中的使用方式,例如,如果你有上面的 compilerOptions 示例,代码如下:

    🌐 This option does not affect how @types/* are included in your application code, for example if you had the above compilerOptions example with code like:

    ts
    import * as moment from "moment";
    moment().format("MMMM Do YYYY, h:mm:ss a");

    moment 导入将具有完整类型定义。

    🌐 The moment import would be fully typed.

    当你设置了此选项时,如果不在 types 数组中包含某个模块,它会:

    🌐 When you have this option set, by not including a module in the types array it:

    • 不会将全局变量添加到你的项目中(例如 node 中的 process 或 Jest 中的 expect
    • 不会将导出显示为自动导入建议

    此功能与typeRoots不同,它仅涉及指定你希望包含的确切类型,而typeRoots则支持指定你想要的特定文件夹。

    🌐 This feature differs from typeRoots in that it is about specifying only the exact types you want included, whereas typeRoots supports saying you want particular folders.

    #触发

    # 声明 - declaration

    为项目中的每个 TypeScript 或 JavaScript 文件生成 .d.ts 文件。这些 .d.ts 文件是类型定义文件,用于描述模块的外部 API。使用 .d.ts 文件,像 TypeScript 这样的工具可以为未定义类型的代码提供智能提示和准确的类型。

    🌐 Generate .d.ts files for every TypeScript or JavaScript file inside your project. These .d.ts files are type definition files which describe the external API of your module. With .d.ts files, tools like TypeScript can provide intellisense and accurate types for un-typed code.

    当将 declaration 设置为 true 时,使用此 TypeScript 代码运行编译器:

    🌐 When declaration is set to true, running the compiler with this TypeScript code:

    ts
    export let helloWorld = "hi";
    Try

    将生成一个像这样的 index.js 文件:

    🌐 Will generate an index.js file like this:

    ts
    export let helloWorld = "hi";
     
    Try

    对应的 helloWorld.d.ts

    🌐 With a corresponding helloWorld.d.ts:

    ts
    export declare let helloWorld: string;
     
    Try

    在处理 JavaScript 的 .d.ts 文件时,你可能希望使用 emitDeclarationOnly 或使用 outDir 来确保 JavaScript 文件不会被覆盖。

    🌐 When working with .d.ts files for JavaScript files you may want to use emitDeclarationOnly or use outDir to ensure that the JavaScript files are not overwritten.

    # 声明目录 - declarationDir

    提供一种配置声明文件触发根目录的方法。

    🌐 Offers a way to configure the root directory for where declaration files are emitted.

    example
    ├── index.ts
    ├── package.json
    └── tsconfig.json

    使用这个 tsconfig.json

    🌐 with this tsconfig.json:

    {
    "": true,
    "": "./types"
    }
    }

    会将 index.ts 的 d.ts 放在 types 文件夹中:

    🌐 Would place the d.ts for the index.ts in a types folder:

    example
    ├── index.js
    ├── index.ts
    ├── package.json
    ├── tsconfig.json
    └── types
    └── index.d.ts

    # 声明映射 - declarationMap

    .d.ts 文件生成源映射,这些映射可以回到原始的 .ts 源文件。这将允许像 VS Code 这样的编辑器在使用类似“转到定义”的功能时跳转到原始的 .ts 文件。

    🌐 Generates a source map for .d.ts files which map back to the original .ts source file. This will allow editors such as VS Code to go to the original .ts file when using features like Go to Definition.

    如果你正在使用项目引用,则应该强烈考虑启用此功能。

    🌐 You should strongly consider turning this on if you’re using project references.

    # 降级迭代 - downlevelIteration

    降级是 TypeScript 用来表示将代码转译为旧版本 JavaScript 的术语。这个标志用于支持在较旧的 JavaScript 运行时中更准确地实现现代 JavaScript 遍历新概念的方法。

    🌐 Downleveling is TypeScript’s term for transpiling to an older version of JavaScript. This flag is to enable support for a more accurate implementation of how modern JavaScript iterates through new concepts in older JavaScript runtimes.

    ECMAScript 6 添加了几种新的迭代原语:for / of 循环(for (el of arr))、数组展开([a, ...b])、参数展开(fn(...args))以及 Symbol.iterator。 如果存在 Symbol.iterator 实现,downlevelIteration 允许在 ES5 环境中更准确地使用这些迭代原语。

    🌐 ECMAScript 6 added several new iteration primitives: the for / of loop (for (el of arr)), Array spread ([a, ...b]), argument spread (fn(...args)), and Symbol.iterator. downlevelIteration allows for these iteration primitives to be used more accurately in ES5 environments if a Symbol.iterator implementation is present.

    示例:对 for / of 的影响

    🌐 Example: Effects on for / of

    使用此 TypeScript 代码:

    🌐 With this TypeScript code:

    ts
    const str = "Hello!";
    for (const s of str) {
    console.log(s);
    }
    Try

    如果未启用 downlevelIteration,对任何对象的 for / of 循环都会降级为传统的 for 循环:

    🌐 Without downlevelIteration enabled, a for / of loop on any object is downleveled to a traditional for loop:

    ts
    "use strict";
    var str = "Hello!";
    for (var _i = 0, str_1 = str; _i < str_1.length; _i++) {
    var s = str_1[_i];
    console.log(s);
    }
     
    Try

    这通常是人们所期望的,但它并不完全符合 ECMAScript 的迭代协议。 某些字符串,例如表情符号 (😜),其 .length 值为 2(甚至更多!),但在 for-of 循环中应作为 1 个单位进行迭代。 有关更详细的说明,请参阅 Jonathan New 的这篇博客文章

    🌐 This is often what people expect, but it’s not 100% compliant with ECMAScript iteration protocol. Certain strings, such as emoji (😜), have a .length of 2 (or even more!), but should iterate as 1 unit in a for-of loop. See this blog post by Jonathan New for a longer explanation.

    当启用 downlevelIteration 时,TypeScript 会使用一个辅助函数来检查是否存在 Symbol.iterator 的实现(无论是原生实现还是填充实现)。如果缺少该实现,将退回到基于索引的迭代方式。

    🌐 When downlevelIteration is enabled, TypeScript will use a helper function that checks for a Symbol.iterator implementation (either native or polyfill). If this implementation is missing, you’ll fall back to index-based iteration.

    ts
    "use strict";
    var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
    next: function () {
    if (o && i >= o.length) o = void 0;
    return { value: o && o[i++], done: !o };
    }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
    };
    var e_1, _a;
    var str = "Hello!";
    try {
    for (var str_1 = __values(str), str_1_1 = str_1.next(); !str_1_1.done; str_1_1 = str_1.next()) {
    var s = str_1_1.value;
    console.log(s);
    }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
    try {
    if (str_1_1 && !str_1_1.done && (_a = str_1.return)) _a.call(str_1);
    }
    finally { if (e_1) throw e_1.error; }
    }
     
    Try

    你也可以通过 importHelpers 使用 tslib 来减少内联 JavaScript 的数量:

    🌐 You can use tslib via importHelpers to reduce the amount of inline JavaScript too:

    ts
    "use strict";
    var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
    next: function () {
    if (o && i >= o.length) o = void 0;
    return { value: o && o[i++], done: !o };
    }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
    };
    var e_1, _a;
    var str = "Hello!";
    try {
    for (var str_1 = __values(str), str_1_1 = str_1.next(); !str_1_1.done; str_1_1 = str_1.next()) {
    var s = str_1_1.value;
    console.log(s);
    }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
    try {
    if (str_1_1 && !str_1_1.done && (_a = str_1.return)) _a.call(str_1);
    }
    finally { if (e_1) throw e_1.error; }
    }
     
    Try

    注意: 如果运行时没有 Symbol.iterator,启用 downlevelIteration 并不会提高合规性。

    示例:对数组扩展的影响

    🌐 Example: Effects on Array Spreads

    这是一个数组展开:

    🌐 This is an array spread:

    js
    // Make a new array whose elements are 1 followed by the elements of arr2
    const arr = [1, ...arr2];

    根据描述,降级到 ES5 听起来很容易:

    🌐 Based on the description, it sounds easy to downlevel to ES5:

    js
    // The same, right?
    const arr = [1].concat(arr2);

    但是,在某些罕见情况下,这明显不同。

    🌐 However, this is observably different in certain rare cases.

    例如,如果源数组缺少一个或多个元素(存在空位),展开语法会将每个空位替换为 undefined,而 .concat 会保持它们不变。

    🌐 For example, if a source array is missing one or more items (contains a hole), the spread syntax will replace each empty item with undefined, whereas .concat will leave them intact.

    js
    // Make an array where the element at index 1 is missing
    let arrayWithHole = ["a", , "c"];
    let spread = [...arrayWithHole];
    let concatenated = [].concat(arrayWithHole);
    console.log(arrayWithHole);
    // [ 'a', <1 empty item>, 'c' ]
    console.log(spread);
    // [ 'a', undefined, 'c' ]
    console.log(concatenated);
    // [ 'a', <1 empty item>, 'c' ]

    就像 for / of 一样,downlevelIteration 将使用 Symbol.iterator(如果存在)来更准确地模拟 ES 6 的行为。

    🌐 Just as with for / of, downlevelIteration will use Symbol.iterator (if present) to more accurately emulate ES 6 behavior.

    # 发出BOM - emitBOM

    控制 TypeScript 在写出输出文件时是否发出 字节顺序标记 (BOM)。 一些运行时环境需要 BOM 才能正确解释 JavaScript 文件;而有些环境则要求文件中不能存在 BOM。 false 的默认值通常是最合适的,除非你有理由更改它。

    🌐 Controls whether TypeScript will emit a byte order mark (BOM) when writing output files. Some runtime environments require a BOM to correctly interpret a JavaScript files; others require that it is not present. The default value of false is generally best unless you have a reason to change it.

    # 仅发出声明 - emitDeclarationOnly

    只生成 .d.ts 文件;不要生成 .js 文件。

    🌐 Only emit .d.ts files; do not emit .js files.

    此设置在两种情况下很有用:

    🌐 This setting is useful in two cases:

    • 你正在使用 TypeScript 以外的转译器来生成 JavaScript。
    • 你正在使用 TypeScript 仅为你的使用者生成 d.ts 文件。

    # 导入助手 - importHelpers

    对于某些降级操作,TypeScript 会使用一些辅助代码来处理诸如继承类、展开数组或对象以及异步操作等任务。默认情况下,这些辅助代码会被插入到使用它们的文件中。如果同一个辅助代码在许多不同的模块中被使用,这可能会导致代码重复。

    🌐 For certain downleveling operations, TypeScript uses some helper code for operations like extending class, spreading arrays or objects, and async operations. By default, these helpers are inserted into files which use them. This can result in code duplication if the same helper is used in many different modules.

    如果 importHelpers 标志开启,这些辅助函数将改为从 tslib 模块导入。你需要确保 tslib 模块能够在运行时被导入。这只影响模块;全局脚本文件不会尝试导入模块。

    🌐 If the importHelpers flag is on, these helper functions are instead imported from the tslib module. You will need to ensure that the tslib module is able to be imported at runtime. This only affects modules; global script files will not attempt to import modules.

    例如,使用此 TypeScript:

    🌐 For example, with this TypeScript:

    ts
    export function fn(arr: number[]) {
    const arr2 = [1, ...arr];
    }

    开启 downlevelIterationimportHelpers 仍然是 false:

    🌐 Turning on downlevelIteration and importHelpers is still false:

    ts
    var __read = (this && this.__read) || function (o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
    while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
    try {
    if (r && !r.done && (m = i["return"])) m.call(i);
    }
    finally { if (e) throw e.error; }
    }
    return ar;
    };
    var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
    if (ar || !(i in from)) {
    if (!ar) ar = Array.prototype.slice.call(from, 0, i);
    ar[i] = from[i];
    }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
    };
    export function fn(arr) {
    var arr2 = __spreadArray([1], __read(arr), false);
    }
     
    Try

    然后同时打开 downlevelIterationimportHelpers

    🌐 Then turning on both downlevelIteration and importHelpers:

    ts
    import { __read, __spreadArray } from "tslib";
    export function fn(arr) {
    var arr2 = __spreadArray([1], __read(arr), false);
    }
     
    Try

    当你提供这些函数的自定义实现时,可以使用 noEmitHelpers

    🌐 You can use noEmitHelpers when you provide your own implementations of these functions.

    # 内联源映射 - inlineSourceMap

    设置后,TypeScript 将不会生成 .js.map 文件来提供源码映射,而是会将源码映射内容嵌入到 .js 文件中。虽然这会导致生成的 JS 文件更大,但在某些情况下可能会很方便。例如,你可能希望在不允许提供 .map 文件的 Web 服务器上调试 JS 文件。

    🌐 When set, instead of writing out a .js.map file to provide source maps, TypeScript will embed the source map content in the .js files. Although this results in larger JS files, it can be convenient in some scenarios. For example, you might want to debug JS files on a webserver that doesn’t allow .map files to be served.

    sourceMap 互斥。

    🌐 Mutually exclusive with sourceMap.

    例如,使用此 TypeScript:

    🌐 For example, with this TypeScript:

    ts
    const helloWorld = "hi";
    console.log(helloWorld);

    转换为此 JavaScript:

    🌐 Converts to this JavaScript:

    ts
    "use strict";
    const helloWorld = "hi";
    console.log(helloWorld);
     
    Try

    然后启用用 inlineSourceMap 构建它,文件底部有一个注释,其中包含该文件的源映射。

    🌐 Then enable building it with inlineSourceMap enabled there is a comment at the bottom of the file which includes a source-map for the file.

    ts
    "use strict";
    const helloWorld = "hi";
    console.log(helloWorld);
    //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDO0FBQ3hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMifQ==
    Try

    # 内联来源 - inlineSources

    设置后,TypeScript 会将 .ts 文件的原始内容作为嵌入字符串包含在源映射中(使用源映射的 sourcesContent 属性)。 这通常在与 inlineSourceMap 相同的情况下非常有用。

    🌐 When set, TypeScript will include the original content of the .ts file as an embedded string in the source map (using the source map’s sourcesContent property). This is often useful in the same cases as inlineSourceMap.

    需要设置 sourceMapinlineSourceMap 中的任意一个。

    🌐 Requires either sourceMap or inlineSourceMap to be set.

    例如,使用此 TypeScript:

    🌐 For example, with this TypeScript:

    ts
    const helloWorld = "hi";
    console.log(helloWorld);
    Try

    默认情况下转换为此 JavaScript:

    🌐 By default converts to this JavaScript:

    ts
    "use strict";
    const helloWorld = "hi";
    console.log(helloWorld);
     
    Try

    然后启用使用 inlineSources 构建,并启用 inlineSourceMap,文件底部有一条注释,其中包含该文件的源映射。请注意,结尾与 inlineSourceMap 中的示例不同,因为源映射现在还包含原始源代码。

    🌐 Then enable building it with inlineSources and inlineSourceMap enabled there is a comment at the bottom of the file which includes a source-map for the file. Note that the end is different from the example in inlineSourceMap because the source-map now contains the original source code also.

    ts
    "use strict";
    const helloWorld = "hi";
    console.log(helloWorld);
    //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDO0FBQ3hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCBoZWxsb1dvcmxkID0gXCJoaVwiO1xuY29uc29sZS5sb2coaGVsbG9Xb3JsZCk7Il19
    Try

    # 地图根目录 - mapRoot

    指定调试器应查找映射文件的位置,而不是生成的位置。这个字符串在源映射中按原样处理,例如:

    🌐 Specify the location where debugger should locate map files instead of generated locations. This string is treated verbatim inside the source-map, for example:

    {
    "": true,
    "": "https://my-website.com/debug/sourcemaps/"
    }
    }

    将声明 index.js 的源映射位于 https://my-website.com/debug/sourcemaps/index.js.map

    🌐 Would declare that index.js will have sourcemaps at https://my-website.com/debug/sourcemaps/index.js.map.

    # 新行 - newLine

    指定在输出文件时使用的行结束序列:‘CRLF’(DOS)或 ‘LF’(Unix)。

    🌐 Specify the end of line sequence to be used when emitting files: ‘CRLF’ (dos) or ‘LF’ (unix).

    • 默认:

      lf

    • 允许:
      • crlf

      • lf

    • 版本:

      1.5

    # 无触发 - noEmit

    不要触发编译器输出文件,如 JavaScript 源代码、源映射或声明。

    🌐 Do not emit compiler output files like JavaScript source code, source-maps or declarations.

    这为另一个工具(如 Babelswc)提供了空间,用于将 TypeScript 文件转换为可以在 JavaScript 环境中运行的文件。

    🌐 This makes room for another tool like Babel, or swc to handle converting the TypeScript file to a file which can run inside a JavaScript environment.

    然后,你可以将 TypeScript 用作提供编辑器集成的工具,并用作源代码类型检查器。

    🌐 You can then use TypeScript as a tool for providing editor integration, and as a source code type-checker.

    # 无触发助手 - noEmitHelpers

    与其通过 importHelpers 导入辅助函数,不如在全局作用域中为你使用的辅助函数提供实现,并完全关闭辅助函数的输出。

    🌐 Instead of importing helpers with importHelpers, you can provide implementations in the global scope for the helpers you use and completely turn off emitting of helper functions.

    例如,在 ES5 中使用这个 async 函数需要一个类似 await 的函数和一个类似 generator 的函数来运行:

    🌐 For example, using this async function in ES5 requires a await-like function and generator-like function to run:

    ts
    const getAPI = async (url: string) => {
    // Get API
    return {};
    };
    Try

    这会创建相当多的 JavaScript:

    🌐 Which creates quite a lot of JavaScript:

    ts
    "use strict";
    var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
    function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
    function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
    function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
    step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
    };
    var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
    return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
    if (f) throw new TypeError("Generator is already executing.");
    while (g && (g = 0, op[0] && (_ = 0)), _) try {
    if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
    if (y = 0, t) op = [op[0] & 2, t.value];
    switch (op[0]) {
    case 0: case 1: t = op; break;
    case 4: _.label++; return { value: op[1], done: false };
    case 5: _.label++; y = op[1]; op = [0]; continue;
    case 7: op = _.ops.pop(); _.trys.pop(); continue;
    default:
    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
    if (t[2]) _.ops.pop();
    _.trys.pop(); continue;
    }
    op = body.call(thisArg, _);
    } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
    if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
    };
    var getAPI = function (url) { return __awaiter(void 0, void 0, void 0, function () {
    return __generator(this, function (_a) {
    // Get API
    return [2 /*return*/, {}];
    });
    }); };
     
    Try

    可以通过此标志将其与你自己的全局变量切换:

    🌐 Which can be switched out with your own globals via this flag:

    ts
    "use strict";
    var getAPI = function (url) { return __awaiter(void 0, void 0, void 0, function () {
    return __generator(this, function (_a) {
    // Get API
    return [2 /*return*/, {}];
    });
    }); };
     
    Try

    # 出错时不输出 - noEmitOnError

    如果报告了任何错误,则不要触发编译器输出文件,如 JavaScript 源代码、源映射或声明。

    🌐 Do not emit compiler output files like JavaScript source code, source-maps or declarations if any errors were reported.

    默认情况下,这将使用 false,使在类似 watch 的环境中使用 TypeScript 更加容易,在这种环境中,你可能希望在确保所有错误都解决之前,先在另一个环境中查看对代码更改的结果。

    🌐 This defaults to false, making it easier to work with TypeScript in a watch-like environment where you may want to see results of changes to your code in another environment before making sure all errors are resolved.

    # 输出目录 - outDir

    如果指定,.js(以及 .d.ts.js.map 等)文件将被输出到此目录中。原始源文件的目录结构将被保留;如果计算出的根目录不是你预期的,请参见 rootDir

    🌐 If specified, .js (as well as .d.ts, .js.map, etc.) files will be emitted into this directory. The directory structure of the original source files is preserved; see rootDir if the computed root is not what you intended.

    如果未指定,.js 文件将被输出到与生成它们的 .ts 文件相同的目录中:

    🌐 If not specified, .js files will be emitted in the same directory as the .ts files they were generated from:

    sh
    $ tsc
    example
    ├── index.js
    └── index.ts

    像这样的 tsconfig.json

    🌐 With a tsconfig.json like this:

    {
    "": "dist"
    }
    }

    使用这些设置运行 tsc 会将文件移动到指定的 dist 文件夹中:

    🌐 Running tsc with these settings moves the files into the specified dist folder:

    sh
    $ tsc
    example
    ├── dist
    │ └── index.js
    ├── index.ts
    └── tsconfig.json

    # 输出文件 - outFile

    如果指定,所有 全局(非模块)文件将被合并成指定的单个输出文件。

    🌐 If specified, all global (non-module) files will be concatenated into the single output file specified.

    如果 modulesystemamd,所有模块文件也将在所有全局内容之后被合并到此文件中。

    🌐 If module is system or amd, all module files will also be concatenated into this file after all global content.

    注意:除非 moduleNoneSystemAMD,否则不能使用 outFile。 此选项不能用于打包 CommonJS 或 ES6 模块。

    🌐 Note: outFile cannot be used unless module is None, System, or AMD. This option cannot be used to bundle CommonJS or ES6 modules.

    # 保留常量枚举 - preserveConstEnums

    不要删除生成代码中的 const enum 声明。const enum 提供了一种方法,通过在运行时发出枚举值而不是引用,来减少应用的整体内存占用。

    🌐 Do not erase const enum declarations in generated code. const enums provide a way to reduce the overall memory footprint of your application at runtime by emitting the enum value instead of a reference.

    例如,使用此 TypeScript:

    🌐 For example with this TypeScript:

    ts
    const enum Album {
    JimmyEatWorldFutures = 1,
    TubRingZooHypothesis = 2,
    DogFashionDiscoAdultery = 3,
    }
     
    const selectedAlbum = Album.JimmyEatWorldFutures;
    if (selectedAlbum === Album.JimmyEatWorldFutures) {
    console.log("That is a great choice.");
    }
    Try

    默认的 const enum 行为是将任何 Album.Something 转换为相应的数字字面量,并完全从 JavaScript 中移除对该枚举的引用。

    🌐 The default const enum behavior is to convert any Album.Something to the corresponding number literal, and to remove a reference to the enum from the JavaScript completely.

    ts
    "use strict";
    const selectedAlbum = 1 /* Album.JimmyEatWorldFutures */;
    if (selectedAlbum === 1 /* Album.JimmyEatWorldFutures */) {
    console.log("That is a great choice.");
    }
     
    Try

    preserveConstEnums 设置为 true 时,enum 会在运行时存在,并且数字仍然会被发出。

    🌐 With preserveConstEnums set to true, the enum exists at runtime and the numbers are still emitted.

    ts
    "use strict";
    var Album;
    (function (Album) {
    Album[Album["JimmyEatWorldFutures"] = 1] = "JimmyEatWorldFutures";
    Album[Album["TubRingZooHypothesis"] = 2] = "TubRingZooHypothesis";
    Album[Album["DogFashionDiscoAdultery"] = 3] = "DogFashionDiscoAdultery";
    })(Album || (Album = {}));
    const selectedAlbum = 1 /* Album.JimmyEatWorldFutures */;
    if (selectedAlbum === 1 /* Album.JimmyEatWorldFutures */) {
    console.log("That is a great choice.");
    }
     
    Try

    这本质上使得这样的 const enums 仅是源代码特性,而不会在运行时留下任何痕迹。

    🌐 This essentially makes such const enums a source-code feature only, with no runtime traces.

    # 删除评论 - removeComments

    在将 TypeScript 文件转换为 JavaScript 时,去除所有注释。默认值为 false

    🌐 Strips all comments from TypeScript files when converting into JavaScript. Defaults to false.

    例如,这是一个具有 JSDoc 注释的 TypeScript 文件:

    🌐 For example, this is a TypeScript file which has a JSDoc comment:

    ts
    /** The translation of 'Hello world' into Portuguese */
    export const helloWorldPTBR = "Olá Mundo";

    removeComments 设置为 true 时:

    🌐 When removeComments is set to true:

    ts
    export const helloWorldPTBR = "Olá Mundo";
     
    Try

    没有设置 removeComments 或将其设为 false 时:

    🌐 Without setting removeComments or having it as false:

    ts
    /** The translation of 'Hello world' into Portuguese */
    export const helloWorldPTBR = "Olá Mundo";
     
    Try

    这意味着你的注释将显示在 JavaScript 代码中。

    🌐 This means that your comments will show up in the JavaScript code.

    # 源映射 - sourceMap

    启用生成sourcemap 文件。 这些文件允许调试器和其他工具在实际使用生成的 JavaScript 文件时显示原始的 TypeScript 源代码。 源映射文件会作为 .js.map(或 .jsx.map)文件与相应的 .js 输出文件一起生成。

    🌐 Enables the generation of sourcemap files. These files allow debuggers and other tools to display the original TypeScript source code when actually working with the emitted JavaScript files. Source map files are emitted as .js.map (or .jsx.map) files next to the corresponding .js output file.

    .js 文件将依次包含一个 source map 注释,用于向外部工具指示文件的位置,例如:

    🌐 The .js files will in turn contain a sourcemap comment to indicate where the files are to external tools, for example:

    ts
    // helloWorld.ts
    export declare const helloWorld = "hi";

    sourceMap 设置为 true 编译会创建以下 JavaScript 文件:

    🌐 Compiling with sourceMap set to true creates the following JavaScript file:

    js
    // helloWorld.js
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.helloWorld = "hi";
    //# sourceMappingURL=// helloWorld.js.map

    这也会生成这个 json 映射:

    🌐 And this also generates this json map:

    json
    // helloWorld.js.map
    {
    "version": 3,
    "file": "ex.js",
    "sourceRoot": "",
    "sources": ["../ex.ts"],
    "names": [],
    "mappings": ";;AAAa,QAAA,UAAU,GAAG,IAAI,CAAA"
    }

    # 源根 - sourceRoot

    指定调试器应查找 TypeScript 文件的位置,而不是相对源位置。这个字符串会在源映射中按原样处理,你可以使用路径或 URL:

    🌐 Specify the location where a debugger should locate TypeScript files instead of relative source locations. This string is treated verbatim inside the source-map where you can use a path or a URL:

    {
    "": true,
    "": "https://my-website.com/debug/source/"
    }
    }

    将声明 index.js 会在 https://my-website.com/debug/source/index.ts 处有一个源文件。

    🌐 Would declare that index.js will have a source file at https://my-website.com/debug/source/index.ts.

    # 剥离内部 - stripInternal

    不要为在其 JSDoc 注释中带有 @internal 注解的代码生成声明。 这是一个内部编译器选项;请自行承担风险使用,因为编译器不会检查结果是否合法。 如果你正在寻找一个工具来处理 d.ts 文件中的额外可见性级别,请查看 api-extractor

    🌐 Do not emit declarations for code that has an @internal annotation in its JSDoc comment. This is an internal compiler option; use at your own risk, because the compiler does not check that the result is valid. If you are searching for a tool to handle additional levels of visibility within your d.ts files, look at api-extractor.

    ts
    /**
    * Days available in a week
    * @internal
    */
    export const daysInAWeek = 7;
     
    /** Calculate how much someone earns in a week */
    export function weeklySalary(dayRate: number) {
    return daysInAWeek * dayRate;
    }
    Try

    当标志设置为 false(默认)时:

    🌐 With the flag set to false (default):

    ts
    /**
    * Days available in a week
    * @internal
    */
    export declare const daysInAWeek = 7;
    /** Calculate how much someone earns in a week */
    export declare function weeklySalary(dayRate: number): number;
     
    Try

    stripInternal 设置为 true 时,发出的 d.ts 将被删除。

    🌐 With stripInternal set to true the d.ts emitted will be redacted.

    ts
    /** Calculate how much someone earns in a week */
    export declare function weeklySalary(dayRate: number): number;
     
    Try

    JavaScript 输出仍然相同。

    🌐 The JavaScript output is still the same.

    • 内部
    • 版本:

      1.5

    #JavaScript 支持

    # 允许 JS - allowJs

    允许在你的项目中导入 JavaScript 文件,而不仅仅是 .ts.tsx 文件。例如,这个 JS 文件:

    🌐 Allow JavaScript files to be imported inside your project, instead of just .ts and .tsx files. For example, this JS file:

    js
    // @filename: card.js
    export const defaultCardDeck = "Heart";
    Try

    导入到 TypeScript 文件中时会引发错误:

    🌐 When imported into a TypeScript file will raise an error:

    ts
    // @filename: index.ts
    import { defaultCardDeck } from "./card";
     
    console.log(defaultCardDeck);
    Try

    在启用 allowJs 时导入正常:

    🌐 Imports fine with allowJs enabled:

    ts
    // @filename: index.ts
    import { defaultCardDeck } from "./card";
     
    console.log(defaultCardDeck);
    Try

    此标志可以用作将 TypeScript 文件逐步添加到 JavaScript 项目中的一种方式,通过允许 .ts.tsx 文件与现有的 JavaScript 文件共存。

    🌐 This flag can be used as a way to incrementally add TypeScript files into JS projects by allowing the .ts and .tsx files to live along-side existing JavaScript files.

    它也可以与 declarationemitDeclarationOnly 一起使用,以 为 JS 文件创建声明

    🌐 It can also be used along-side declaration and emitDeclarationOnly to create declarations for JS files.

    # 检查 JS - checkJs

    allowJs协同工作。当启用checkJs时,会在 JavaScript 文件中报告错误。这相当于在项目中包含的所有 JavaScript 文件顶部加入// @ts-check

    🌐 Works in tandem with allowJs. When checkJs is enabled then errors are reported in JavaScript files. This is the equivalent of including // @ts-check at the top of all JavaScript files which are included in your project.

    例如,根据 TypeScript 附带的 parseFloat 类型定义,这是不正确的 JavaScript:

    🌐 For example, this is incorrect JavaScript according to the parseFloat type definition which comes with TypeScript:

    js
    // parseFloat only takes a string
    module.exports.pi = parseFloat(3.142);

    导入到 TypeScript 模块中时:

    🌐 When imported into a TypeScript module:

    ts
    // @filename: constants.js
    module.exports.pi = parseFloat(3.142);
     
    // @filename: index.ts
    import { pi } from "./constants";
    console.log(pi);
    Try

    你不会收到任何错误。但是,如果你开启 checkJs,你将会从 JavaScript 文件中收到错误信息。

    🌐 You will not get any errors. However, if you turn on checkJs then you will get error messages from the JavaScript file.

    ts
    // @filename: constants.js
    module.exports.pi = parseFloat(3.142);
    Argument of type 'number' is not assignable to parameter of type 'string'.2345Argument of type 'number' is not assignable to parameter of type 'string'.
     
    // @filename: index.ts
    import { pi } from "./constants";
    console.log(pi);
    Try

    # 最大节点模块 JS 深度 - maxNodeModuleJsDepth

    node_modules 下搜索的最大依赖深度并加载 JavaScript 文件。

    🌐 The maximum dependency depth to search under node_modules and load JavaScript files.

    此标志仅在启用 allowJs 时使用,并且当你希望 TypeScript 推断 node_modules 中所有 JavaScript 的类型时使用。

    🌐 This flag can only be used when allowJs is enabled, and is used if you want to have TypeScript infer types for all of the JavaScript inside your node_modules.

    理想情况下,这应保持为 0(默认值),并且应该使用 d.ts 文件来明确定义模块的形状。然而,在某些情况下,你可能希望开启此选项,但需要以牺牲速度和潜在准确性为代价。

    🌐 Ideally this should stay at 0 (the default), and d.ts files should be used to explicitly define the shape of modules. However, there are cases where you may want to turn this on at the expense of speed and potential accuracy.

    #编辑器支持

    # 禁用大小限制 - disableSizeLimit

    为了在处理非常大的 JavaScript 项目时避免可能的内存膨胀问题,TypeScript 会对分配的内存量设定上限。打开此选项将取消该限制。

    🌐 To avoid a possible memory bloat issues when working with very large JavaScript projects, there is an upper limit to the amount of memory TypeScript will allocate. Turning this flag on will remove the limit.

    # 插件 - plugins

    在编辑器内运行的语言服务插件列表。

    🌐 List of language service plugins to run inside the editor.

    语言服务插件是一种基于现有 TypeScript 文件向用户提供额外信息的方式。它们可以增强 TypeScript 与编辑器之间的现有消息,或提供自己的错误信息。

    🌐 Language service plugins are a way to provide additional information to a user based on existing TypeScript files. They can enhance existing messages between TypeScript and an editor, or to provide their own error messages.

    例如:

    🌐 For example:

    VS Code 具有让扩展自动包含语言服务插件的功能,因此你可能在编辑器中已经有一些在运行,而无需在你的 tsconfig.json 中定义它们。

    🌐 VS Code has the ability for a extension to automatically include language service plugins, and so you may have some running in your editor without needing to define them in your tsconfig.json.

    #互操作性约束

    # 允许合成默认导入 - allowSyntheticDefaultImports

    当设置为 true 时,allowSyntheticDefaultImports 允许你这样写导入语句:

    🌐 When set to true, allowSyntheticDefaultImports allows you to write an import like:

    ts
    import React from "react";

    而不是:

    🌐 instead of:

    ts
    import * as React from "react";

    当模块没有明确指定默认导出时。

    🌐 When the module does not explicitly specify a default export.

    例如,如果没有 allowSyntheticDefaultImports 为真:

    🌐 For example, without allowSyntheticDefaultImports as true:

    ts
    // @filename: utilFunctions.js
    const getStringLength = (str) => str.length;
     
    module.exports = {
    getStringLength,
    };
     
    // @filename: index.ts
    import utils from "./utilFunctions";
     
    const count = utils.getStringLength("Check JS");
    Try

    这段代码会报错,因为没有一个可以导入的 default 对象。尽管感觉上它应该存在。为了方便,像 Babel 这样的转译器会在没有创建默认导出的情况下自动创建一个默认导出,使模块看起来更像这样:

    🌐 This code raises an error because there isn’t a default object which you can import. Even though it feels like it should. For convenience, transpilers like Babel will automatically create a default if one isn’t created. Making the module look a bit more like:

    js
    // @filename: utilFunctions.js
    const getStringLength = (str) => str.length;
    const allFunctions = {
    getStringLength,
    };
    module.exports = allFunctions;
    module.exports.default = allFunctions;

    这个标志不会影响 TypeScript 生成的 JavaScript,它仅用于类型检查。 这个选项使 TypeScript 的行为与 Babel 保持一致,Babel 会生成额外的代码以使使用模块的默认导出更加方便。

    🌐 This flag does not affect the JavaScript emitted by TypeScript, it’s only for the type checking. This option brings the behavior of TypeScript in-line with Babel, where extra code is emitted to make using a default export of a module more ergonomic.

    # 仅可擦除语法 - erasableSyntaxOnly

    自 v23.6 起,Node.js 支持直接运行 TypeScript 文件;然而,在此模式下,仅支持没有运行时语义的 TypeScript 特定语法。换句话说,必须可以轻松地删除文件中的任何 TypeScript 特定语法,从而保留下一个有效的 JavaScript 文件。

    🌐 Node.js supports running TypeScript files directly as of v23.6; however, only TypeScript-specific syntax that does not have runtime semantics are supported under this mode. In other words, it must be possible to easily erase any TypeScript-specific syntax from a file, leaving behind a valid JavaScript file.

    这意味着不支持以下构造:

    🌐 That means the following constructs are not supported:

    • enum 声明
    • namespacemodule 的运行时代码
    • 类中的参数属性
    • 非 ECMAScript import =export = 赋值
    • <prefix> 风格的类型断言
    ts
    // ❌ error: An `import ... = require(...)` alias
    import foo = require("foo");
    // ❌ error: A namespace with runtime code.
    namespace container {
    foo.method();
    export type Bar = string;
    }
    // ❌ error: An `import =` alias
    import Bar = container.Bar;
    class Point {
    // ❌ error: Parameter properties
    constructor(public x: number, public y: number) {}
    }
    // ❌ error: An `export =` assignment.
    export = Point;
    // ❌ error: An enum declaration.
    enum Direction {
    Up,
    Down,
    Left,
    Right,
    }
    // ❌ error: <prefix>-style type assertion.
    const num = <number>1;

    类似的工具如 ts-blank-spaceAmaro(Node.js 中用于类型剥离的底层库)也有同样的限制。这些工具在遇到不符合这些要求的代码时,会提供有用的错误提示,但你仍然要到真正运行代码时才会发现它不能正常工作。

    🌐 Similar tools like ts-blank-space or Amaro (the underlying library for type-stripping in Node.js) have the same limitations. These tools will provide helpful error messages if they encounter code that doesn’t meet these requirements, but you still won’t find out your code doesn’t work until you actually try to run it.

    --erasableSyntaxOnly 标志会导致 TypeScript 对大多数具有运行时行为的 TypeScript 特定结构报错。

    🌐 The --erasableSyntaxOnly flag will cause TypeScript to error on most TypeScript-specific constructs that have runtime behavior.

    ts
    class C {
    constructor(public x: number) { }
    // ~~~~~~~~~~~~~~~~
    // error! This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
    }
    }

    通常,你会希望将此标志与 --verbatimModuleSyntax 结合使用,它可以确保模块包含适当的导入语法,并且不会进行导入省略。

    🌐 Typically, you will want to combine this flag with the --verbatimModuleSyntax, which ensures that a module contains the appropriate import syntax, and that import elision does not take place.

      # ES 模块互操作 - esModuleInterop

      默认情况下(当 esModuleInterop 为 false 或未设置时),TypeScript 会将 CommonJS/AMD/UMD 模块类似于 ES6 模块来处理。在这样做的过程中,有两个部分尤其是存在错误假设:

      🌐 By default (with esModuleInterop false or not set) TypeScript treats CommonJS/AMD/UMD modules similar to ES6 modules. In doing this, there are two parts in particular which turned out to be flawed assumptions:

      • import * as moment from "moment" 这样的命名空间导入,其作用与 const moment = require("moment") 相同
      • import moment from "moment" 这样的默认导入与 const moment = require("moment").default 的作用相同

      这种不匹配会导致以下两个问题:

      🌐 This mis-match causes these two issues:

      • ES6 模块规范指出,命名空间导入(import * as x)只能是一个对象,但通过让 TypeScript 将其视为与 = require("x") 相同,TypeScript 允许将该导入视为函数并可调用。根据规范,这是不合法的。
      • 虽然符合 ES6 模块规范,但大多数带有 CommonJS/AMD/UMD 模块的库并不像 TypeScript 的实现那样严格遵守。

      开启 esModuleInterop 会修复 TypeScript 转译代码中的这两个问题。第一个是在编译器中更改行为,第二个通过两个新的辅助函数修复,它们提供了一个垫片以确保生成的 JavaScript 的兼容性:

      🌐 Turning on esModuleInterop will fix both of these problems in the code transpiled by TypeScript. The first changes the behavior in the compiler, the second is fixed by two new helper functions which provide a shim to ensure compatibility in the emitted JavaScript:

      ts
      import * as fs from "fs";
      import _ from "lodash";
      fs.readFileSync("file.txt", "utf8");
      _.chunk(["a", "b", "c", "d"], 2);

      禁用 esModuleInterop 后:

      🌐 With esModuleInterop disabled:

      ts
      "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);
       
      Try

      esModuleInterop 设置为 true 后:

      🌐 With esModuleInterop set to true:

      ts
      "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 () {
      var ownKeys = function(o) {
      ownKeys = Object.getOwnPropertyNames || function (o) {
      var ar = [];
      for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
      return ar;
      };
      return ownKeys(o);
      };
      return function (mod) {
      if (mod && mod.__esModule) return mod;
      var result = {};
      if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
      __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);
       
      Try

      注:命名空间导入 import * as fs from "fs" 仅考虑导入对象上拥有 的属性(基本上是直接在对象上设置的属性,而不是通过原型链继承的属性)。如果你导入的模块使用继承属性定义其 API,你需要使用默认导入形式 (import fs from "fs"),或者禁用 esModuleInterop

      🌐 Note: The namespace import import * as fs from "fs" only accounts for properties which are owned (basically properties set on the object and not via the prototype chain) on the imported object. If the module you’re importing defines its API using inherited properties, you need to use the default import form (import fs from "fs"), or disable esModuleInterop.

      注意:你可以通过启用 importHelpers 让 JS 输出更精简:

      🌐 Note: You can make JS emit terser by enabling importHelpers:

      ts
      "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);
       
      Try

      启用 esModuleInterop 也将启用 allowSyntheticDefaultImports

      🌐 Enabling esModuleInterop will also enable allowSyntheticDefaultImports.

      # 强制文件名使用一致的大小写 - forceConsistentCasingInFileNames

      TypeScript 遵循其运行所在文件系统的大小写敏感规则。如果一些开发者在大小写敏感的文件系统上工作,而其他人则不是,这可能会带来问题。如果一个文件尝试通过指定 ./FileManager.ts 来导入 fileManager.ts,在大小写不敏感的文件系统中可以找到该文件,但在大小写敏感的文件系统中则找不到。

      🌐 TypeScript follows the case sensitivity rules of the file system it’s running on. This can be problematic if some developers are working in a case-sensitive file system and others aren’t. If a file attempts to import fileManager.ts by specifying ./FileManager.ts the file will be found in a case-insensitive file system, but not on a case-sensitive file system.

      设置此选项后,如果程序尝试包含大小写与磁盘上的大小写不同的文件,TypeScript 将触发错误。

      🌐 When this option is set, TypeScript will issue an error if a program tries to include a file by a casing different from the casing on disk.

      • 推荐
      • 默认:

        true

      • 版本:

        1.8

      # isolatedDeclarations - isolatedDeclarations

      要求在导出时进行足够的注释,以便其他工具可以轻松生成声明文件。

      🌐 Require sufficient annotation on exports so other tools can trivially generate declaration files.

      欲了解更多信息,请参阅 5.5 版本说明

      🌐 For more information, see the 5.5 release notes

      # 独立模块 - isolatedModules

      虽然你可以使用 TypeScript 将 TypeScript 代码生成 JavaScript 代码,但使用其他转译器(如 Babel)来完成这一操作也很常见。然而,其他转译器一次只能处理单个文件,这意味着它们无法应用依赖于完整类型系统理解的代码转换。这个限制同样适用于 TypeScript 的 ts.transpileModule API,一些构建工具会使用该 API。

      🌐 While you can use TypeScript to produce JavaScript code from TypeScript code, it’s also common to use other transpilers such as Babel to do this. However, other transpilers only operate on a single file at a time, which means they can’t apply code transforms that depend on understanding the full type system. This restriction also applies to TypeScript’s ts.transpileModule API which is used by some build tools.

      这些限制可能会导致某些 TypeScript 特性(例如 const enumnamespace)在运行时出现问题。设置 isolatedModules 标志会在你编写某些无法通过单文件转译过程正确解释的代码时,提醒 TypeScript 给出警告。

      🌐 These limitations can cause runtime problems with some TypeScript features like const enums and namespaces. Setting the isolatedModules flag tells TypeScript to warn you if you write certain code that can’t be correctly interpreted by a single-file transpilation process.

      它不会改变代码的行为,也不会改变 TypeScript 检查和触发过程的行为。

      🌐 It does not change the behavior of your code, or otherwise change the behavior of TypeScript’s checking and emitting process.

      当启用 isolatedModules 时无法工作的部分代码示例。

      🌐 Some examples of code which does not work when isolatedModules is enabled.

      非值标识符的导出

      🌐 Exports of Non-Value Identifiers

      在 TypeScript 中,你可以导入一个类型,然后随后导出它:

      🌐 In TypeScript, you can import a type and then subsequently export it:

      ts
      import { someType, someFunction } from "someModule";
       
      someFunction();
       
      export { someType, someFunction };
      Try

      因为 someType 没有值,生成的 export 将不会尝试导出它(在 JavaScript 中这将是一个运行时错误):

      🌐 Because there’s no value for someType, the emitted export will not try to export it (this would be a runtime error in JavaScript):

      js
      export { someFunction };

      单文件转换器无法知道 someType 是否会产生一个值,因此导出仅引用类型的名称是错误的。

      🌐 Single-file transpilers don’t know whether someType produces a value or not, so it’s an error to export a name that only refers to a type.

      非模块文件

      🌐 Non-Module Files

      如果设置了 isolatedModules,命名空间只允许出现在 模块 中(这意味着它具有某种形式的 import/export)。如果在非模块文件中发现命名空间,则会发生错误:

      🌐 If isolatedModules is set, namespaces are only allowed in modules (which means it has some form of import/export). An error occurs if a namespace is found in a non-module file:

      ts
      namespace Instantiated {
      Namespaces are not allowed in global script files when 'isolatedModules' is enabled. If this file is not intended to be a global script, set 'moduleDetection' to 'force' or add an empty 'export {}' statement.1280Namespaces are not allowed in global script files when 'isolatedModules' is enabled. If this file is not intended to be a global script, set 'moduleDetection' to 'force' or add an empty 'export {}' statement.
      export const x = 1;
      }
      Try

      此限制不适用于 .d.ts 文件。

      🌐 This restriction doesn’t apply to .d.ts files.

      const enum 成员的参考

      🌐 References to const enum members

      在 TypeScript 中,当你引用一个 const enum 成员时,该引用会在生成的 JavaScript 中被其实际值替换。修改这个 TypeScript:

      🌐 In TypeScript, when you reference a const enum member, the reference is replaced by its actual value in the emitted JavaScript. Changing this TypeScript:

      ts
      declare const enum Numbers {
      Zero = 0,
      One = 1,
      }
      console.log(Numbers.Zero + Numbers.One);
      Try

      到这个 JavaScript:

      🌐 To this JavaScript:

      ts
      "use strict";
      console.log(0 + 1);
       
      Try

      如果不知道这些成员的值,其他转译器无法替换对 Numbers 的引用,如果不处理会导致运行时错误(因为在运行时没有 Numbers 对象)。因此,当设置 isolatedModules 时,引用环境中的 const enum 成员是错误的。

      🌐 Without knowledge of the values of these members, other transpilers can’t replace the references to Numbers, which would be a runtime error if left alone (since there are no Numbers object at runtime). Because of this, when isolatedModules is set, it is an error to reference an ambient const enum member.

      这是为了在 Node.js 中反映相同的标志;它不会解析符号链接的实际路径。

      🌐 This is to reflect the same flag in Node.js; which does not resolve the real path of symlinks.

      这个标志的行为也与 Webpack 的 resolve.symlinks 选项相反(即将 TypeScript 的 preserveSymlinks 设置为 true 相当于将 Webpack 的 resolve.symlinks 设置为 false,反之亦然)。

      🌐 This flag also exhibits the opposite behavior to Webpack’s resolve.symlinks option (i.e. setting TypeScript’s preserveSymlinks to true parallels setting Webpack’s resolve.symlinks to false, and vice-versa).

      启用此功能后,对模块和包的引用(例如 import/// <reference type="..." /> 指令)都将相对于符号链接文件的位置进行解析,而不是相对于符号链接所解析到的路径进行解析。

      🌐 With this enabled, references to modules and packages (e.g. imports and /// <reference type="..." /> directives) are all resolved relative to the location of the symbolic link file, rather than relative to the path that the symbolic link resolves to.

      # 逐字模块语法 - verbatimModuleSyntax

      默认情况下,TypeScript 会执行一种称为导入省略的操作。基本上,如果你写了类似这样的内容

      🌐 By default, TypeScript does something called import elision. Basically, if you write something like

      ts
      import { Car } from "./car";
      export function drive(car: Car) {
      // ...
      }

      TypeScript 会检测到你只是在使用类型的导入,并会完全删除该导入。 你的输出 JavaScript 可能看起来像这样:

      🌐 TypeScript detects that you’re only using an import for types and drops the import entirely. Your output JavaScript might look something like this:

      js
      export function drive(car) {
      // ...
      }

      大多数情况下这是好的,因为如果 Car 不是从 ./car 导出的值,我们就会遇到运行时错误。

      🌐 Most of the time this is good, because if Car isn’t a value that’s exported from ./car, we’ll get a runtime error.

      但对于某些边缘情况,它确实增加了一层复杂性。例如,请注意没有像 import "./car"; 这样的语句——导入被完全删除了。对于有副作用的模块或没有副作用的模块来说,这实际上是有区别的。

      🌐 But it does add a layer of complexity for certain edge cases. For example, notice there’s no statement like import "./car"; - the import was dropped entirely. That actually makes a difference for modules that have side-effects or not.

      TypeScript 对 JavaScript 的输出策略还有另外几层复杂性——导入消除并不总是仅由导入的使用方式决定——它通常还会参考值是如何声明的。 所以像下面这样的代码并不总是很清楚

      🌐 TypeScript’s emit strategy for JavaScript also has another few layers of complexity - import elision isn’t always just driven by how an import is used - it often consults how a value is declared as well. So it’s not always clear whether code like the following

      ts
      export { Car } from "./car";

      应该被保留或丢弃。 如果 Car 是用类似 class 的东西声明的,那么它可以在生成的 JavaScript 文件中保留。 但如果 Car 仅被声明为 type 别名或 interface,那么 JavaScript 文件根本不应该导出 Car

      🌐 should be preserved or dropped. If Car is declared with something like a class, then it can be preserved in the resulting JavaScript file. But if Car is only declared as a type alias or interface, then the JavaScript file shouldn’t export Car at all.

      虽然 TypeScript 可能能够根据来自各个文件的信息做出这些触发决定,但并非每个编译器都可以。

      🌐 While TypeScript might be able to make these emit decisions based on information from across files, not every compiler can.

      导入和导出上的 type 修饰符在这些情况下有一定帮助。我们可以明确指出某个导入或导出仅用于类型分析,并且在 JavaScript 文件中可以通过使用 type 修饰符将其完全省略。

      🌐 The type modifier on imports and exports helps with these situations a bit. We can make it explicit whether an import or export is only being used for type analysis, and can be dropped entirely in JavaScript files by using the type modifier.

      ts
      // This statement can be dropped entirely in JS output
      import type * as car from "./car";
      // The named import/export 'Car' can be dropped in JS output
      import { type Car } from "./car";
      export { type Car } from "./car";

      type 修饰符本身并不是特别有用——默认情况下,模块省略仍然会去掉导入,而且没有任何东西强制你区分 type 和普通的导入与导出。因此 TypeScript 提供了 --importsNotUsedAsValues 标志以确保你使用 type 修饰符,--preserveValueImports 用于防止某些模块省略行为,--isolatedModules 确保你的 TypeScript 代码可以在不同的编译器中正常工作。不幸的是,理解这三个标志的具体细节比较困难,而且仍然存在一些意外行为的边缘情况。

      TypeScript 5.0 引入了一个名为 --verbatimModuleSyntax 的新选项来简化这种情况。规则更简单——任何没有 type 修饰符的导入或导出都会保留下来。任何使用 type 修饰符的内容都会被完全移除。

      🌐 TypeScript 5.0 introduces a new option called --verbatimModuleSyntax to simplify the situation. The rules are much simpler - any imports or exports without a type modifier are left around. Anything that uses the type modifier is dropped entirely.

      ts
      // Erased away entirely.
      import type { A } from "a";
      // Rewritten to 'import { b } from "bcd";'
      import { b, type c, type d } from "bcd";
      // Rewritten to 'import {} from "xyz";'
      import { type xyz } from "xyz";

      有了这个新选项,所见即所得。

      🌐 With this new option, what you see is what you get.

      不过在模块互操作方面,这确实有一些影响。在启用此标志时,当你的设置或文件扩展名暗示了不同的模块系统时,ECMAScript importexport 不会被重写为 require 调用。取而代之的,你会收到一个错误。如果你需要生成使用 requiremodule.exports 的代码,你必须使用早于 ES2015 的 TypeScript 模块语法:

      🌐 That does have some implications when it comes to module interop though. Under this flag, ECMAScript imports and exports won’t be rewritten to require calls when your settings or file extension implied a different module system. Instead, you’ll get an error. If you need to emit code that uses require and module.exports, you’ll have to use TypeScript’s module syntax that predates ES2015:

      输入 TypeScript 输出 JavaScript
      ts
      import foo = require("foo");
      js
      const foo = require("foo");
      ts
      function foo() {}
      function bar() {}
      function baz() {}
      export = {
      foo,
      bar,
      baz,
      };
      js
      function foo() {}
      function bar() {}
      function baz() {}
      module.exports = {
      foo,
      bar,
      baz,
      };

      虽然这是一个限制,但它确实有助于让一些问题更加明显。例如,非常常见的情况是忘记在 --module node16 下设置 package.jsontype 字段。因此,开发者可能会在不自觉的情况下开始编写 CommonJS 模块而不是 ES 模块,从而导致意外的查找规则和 JavaScript 输出。这个新标志确保你对所使用的文件类型是有意选择的,因为语法是刻意不同的。

      🌐 While this is a limitation, it does help make some issues more obvious. For example, it’s very common to forget to set the type field in package.json under --module node16. As a result, developers would start writing CommonJS modules instead of ES modules without realizing it, giving surprising lookup rules and JavaScript output. This new flag ensures that you’re intentional about the file type you’re using because the syntax is intentionally different.

      因为 --verbatimModuleSyntax 提供的情况比 --importsNotUsedAsValues--preserveValueImports 更一致,所以这两个现有的标记将被淘汰,以支持 --verbatimModuleSyntax

      🌐 Because --verbatimModuleSyntax provides a more consistent story than --importsNotUsedAsValues and --preserveValueImports, those two existing flags are being deprecated in its favor.

      欲了解更多详情,请查阅原始拉取请求其提案问题

      🌐 For more details, read up on the original pull request and its proposal issue.

      #向后兼容

      # 字符集 - charset

      在之前的 TypeScript 版本中,这控制了从磁盘读取文本文件时使用的编码。今天,TypeScript 假设使用 UTF-8 编码,但会正确检测 UTF-16(大端和小端)或 UTF-8 BOM。

      🌐 In prior versions of TypeScript, this controlled what encoding was used when reading text files from disk. Today, TypeScript assumes UTF-8 encoding, but will correctly detect UTF-16 (BE and LE) or UTF-8 BOMs.

      • 弃用
      • 默认:

        utf8

      • 版本:

        1.0

      # 导入未用作值 - importsNotUsedAsValues

      已弃用,建议使用 verbatimModuleSyntax

      🌐 Deprecated in favor of verbatimModuleSyntax.

      此标志控制 import 的工作方式,有三种不同的选项:

      🌐 This flag controls how import works, there are 3 different options:

      • remove:默认行为是丢弃仅引用类型的 import 语句。
      • preserve:保留所有值或类型从未被使用的 import 语句。这可能会导致导入或副作用被保留。
      • error:这会保留所有导入(与 preserve 选项相同),但当值导入仅用作类型时会报错。如果你想确保没有值被意外导入,同时仍然明确副作用导入,这可能会很有用。

      这个标志之所以有效,是因为你可以使用 import type 明确创建一个 import 语句,而这个语句永远不应该被输出到 JavaScript 中。

      🌐 This flag works because you can use import type to explicitly create an import statement which should never be emitted into JavaScript.

      # 仅限字符串的键 - keyofStringsOnly

      此标志会将 keyof 类型运算符更改为在应用于具有字符串索引签名的类型时返回 string 而不是 string | number

      🌐 This flag changes the keyof type operator to return string instead of string | number when applied to a type with a string index signature.

      此标志用于帮助人们避免这种行为(出现在 TypeScript 2.9 发行之前)。

      🌐 This flag is used to help people keep this behavior from before TypeScript 2.9’s release.

      • 弃用
      • 版本:

        2.9

      # 不使用隐式严格模式 - noImplicitUseStrict

      你不应该需要这个。默认情况下,当向非 ES6 目标发出模块文件时,TypeScript 会在文件顶部发出一个 "use strict"; 前置声明。 此设置用于禁用该前置声明。

      🌐 You shouldn’t need this. By default, when emitting a module file to a non-ES6 target, TypeScript emits a "use strict"; prologue at the top of the file. This setting disables the prologue.

      # 没有严格的通用检查 - noStrictGenericChecks

      TypeScript 将在比较两个泛型函数时统一类型参数。

      🌐 TypeScript will unify type parameters when comparing two generic functions.

      ts
      type A = <T, U>(x: T, y: U) => [T, U];
      type B = <S>(x: S, y: S) => [S, S];
       
      function f(a: A, b: B) {
      b = a; // Ok
      a = b; // Error
      Type 'B' is not assignable to type 'A'. Types of parameters 'y' and 'y' are incompatible. Type 'U' is not assignable to type 'T'. 'T' could be instantiated with an arbitrary type which could be unrelated to 'U'.2322Type 'B' is not assignable to type 'A'. Types of parameters 'y' and 'y' are incompatible. Type 'U' is not assignable to type 'T'. 'T' could be instantiated with an arbitrary type which could be unrelated to 'U'.
      }
      Try

      此标志可用于删除该检查。

      🌐 This flag can be used to remove that check.

      # 出去 - out

      请改用 outFile

      🌐 Use outFile instead.

      out 选项以一种不可预测或不一致的方式计算最终文件位置。此选项仅为向后兼容而保留,已被弃用。

      🌐 The out option computes the final file location in a way that is not predictable or consistent. This option is retained for backward compatibility only and is deprecated.

      # 保留数值导入 - preserveValueImports

      已弃用,建议使用 verbatimModuleSyntax

      🌐 Deprecated in favor of verbatimModuleSyntax.

      在某些情况下,TypeScript 无法检测到你正在使用某个导入。例如,看看以下代码:

      🌐 There are some cases where TypeScript can’t detect that you’re using an import. For example, take the following code:

      ts
      import { Animal } from "./animal.js";
      eval("console.log(new Animal().isDangerous())");

      或者使用“编译成 HTML”的语言如 Svelte 或 Vue 编写代码。preserveValueImports 会阻止 TypeScript 删除该导入,即使它看起来未被使用。

      🌐 or code using ‘Compiles to HTML’ languages like Svelte or Vue. preserveValueImports will prevent TypeScript from removing the import, even if it appears unused.

      当与 isolatedModules 结合使用时:导入的类型 必须 标记为仅类型,因为一次处理单个文件的编译器无法判断导入的是未使用的值,还是必须删除的类型,以避免运行时崩溃。

      🌐 When combined with isolatedModules: imported types must be marked as type-only because compilers that process single files at a time have no way of knowing whether imports are values that appear unused, or a type that must be removed in order to avoid a runtime crash.

      # 抑制多余属性错误 - suppressExcessPropertyErrors

      这会禁用多余属性错误的报告,例如以下示例中所示的错误:

      🌐 This disables reporting of excess property errors, such as the one shown in the following example:

      ts
      type Point = { x: number; y: number };
      const p: Point = { x: 1, y: 3, m: 10 };
      Object literal may only specify known properties, and 'm' does not exist in type 'Point'.2353Object literal may only specify known properties, and 'm' does not exist in type 'Point'.
      Try

      添加此标志是为了帮助人们过渡到 TypeScript 1.6 中对新对象字面量的更严格检查。

      🌐 This flag was added to help people migrate to the stricter checking of new object literals in TypeScript 1.6.

      我们不建议在现代代码库中使用此标志,如果有必要,可以使用 // @ts-ignore 来抑制一次性情况。

      🌐 We don’t recommend using this flag in a modern codebase, you can suppress one-off cases where you need it using // @ts-ignore.

      # 抑制隐式 Any 索引错误 - suppressImplicitAnyIndexErrors

      开启 suppressImplicitAnyIndexErrors 会禁止在对对象进行索引时报告关于隐式 any 的错误,如以下示例所示:

      🌐 Turning suppressImplicitAnyIndexErrors on suppresses reporting the error about implicit anys when indexing into objects, as shown in the following example:

      ts
      const obj = { x: 10 };
      console.log(obj["foo"]);
      Element implicitly has an 'any' type because expression of type '"foo"' can't be used to index type '{ x: number; }'. Property 'foo' does not exist on type '{ x: number; }'.7053Element implicitly has an 'any' type because expression of type '"foo"' can't be used to index type '{ x: number; }'. Property 'foo' does not exist on type '{ x: number; }'.
      Try

      使用 suppressImplicitAnyIndexErrors 是一种相当激烈的方法。建议改为使用 @ts-ignore 注释:

      🌐 Using suppressImplicitAnyIndexErrors is quite a drastic approach. It is recommended to use a @ts-ignore comment instead:

      ts
      const obj = { x: 10 };
      // @ts-ignore
      console.log(obj["foo"]);
      Try

      #语言与环境

      # 发出装饰器元数据 - emitDecoratorMetadata

      启用对装饰器发出类型元数据的实验性支持,该功能可与模块 reflect-metadata 一起使用。

      🌐 Enables experimental support for emitting type metadata for decorators which works with the module reflect-metadata.

      例如,这是 TypeScript

      🌐 For example, here is the TypeScript

      ts
      function LogMethod(
      target: any,
      propertyKey: string | symbol,
      descriptor: PropertyDescriptor
      ) {
      console.log(target);
      console.log(propertyKey);
      console.log(descriptor);
      }
       
      class Demo {
      @LogMethod
      public foo(bar: number) {
      // do nothing
      }
      }
       
      const demo = new Demo();
      Try

      emitDecoratorMetadata 未设置为 true(默认值)的情况下,生成的 JavaScript 为:

      🌐 With emitDecoratorMetadata not set to true (default) the emitted JavaScript is:

      ts
      "use strict";
      var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
      var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
      if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
      else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
      return c > 3 && r && Object.defineProperty(target, key, r), r;
      };
      function LogMethod(target, propertyKey, descriptor) {
      console.log(target);
      console.log(propertyKey);
      console.log(descriptor);
      }
      class Demo {
      foo(bar) {
      // do nothing
      }
      }
      __decorate([
      LogMethod
      ], Demo.prototype, "foo", null);
      const demo = new Demo();
       
      Try

      emitDecoratorMetadata 设置为 true 时,生成的 JavaScript 为:

      🌐 With emitDecoratorMetadata set to true the emitted JavaScript is:

      ts
      "use strict";
      var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
      var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
      if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
      else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
      return c > 3 && r && Object.defineProperty(target, key, r), r;
      };
      var __metadata = (this && this.__metadata) || function (k, v) {
      if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
      };
      function LogMethod(target, propertyKey, descriptor) {
      console.log(target);
      console.log(propertyKey);
      console.log(descriptor);
      }
      class Demo {
      foo(bar) {
      // do nothing
      }
      }
      __decorate([
      LogMethod,
      __metadata("design:type", Function),
      __metadata("design:paramtypes", [Number]),
      __metadata("design:returntype", void 0)
      ], Demo.prototype, "foo", null);
      const demo = new Demo();
       
      Try

      # 实验性装饰器 - experimentalDecorators

      启用 装饰器的实验性支持,这是一种早于 TC39 标准化过程的装饰器版本。

      🌐 Enables experimental support for decorators, which is a version of decorators that predates the TC39 standardization process.

      装饰器是一种尚未完全被纳入 JavaScript 规范的语言特性。这意味着在 TypeScript 中的实现版本可能与 TC39 决定时 JavaScript 中的实现有所不同。

      🌐 Decorators are a language feature which hasn’t yet been fully ratified into the JavaScript specification. This means that the implementation version in TypeScript may differ from the implementation in JavaScript when it is decided by TC39.

      你可以在 手册 中了解有关 TypeScript 中装饰器支持的更多信息。

      🌐 You can find out more about decorator support in TypeScript in the handbook.

      # JSX - jsx

      控制 JSX 构造在 JavaScript 文件中的输出方式。这仅影响从 .tsx 文件开始的 JS 文件的输出。

      🌐 Controls how JSX constructs are emitted in JavaScript files. This only affects output of JS files that started in .tsx files.

      • react-jsx:生成 .js 文件,将 JSX 更改为适合生产的 _jsx 调用
      • react-jsxdev:仅在开发时将 .js 文件中的 JSX 改为 _jsx 调用
      • preserve:生成 .jsx 文件,JSX 保持不变
      • react-native:输出 .js 文件,JSX 保持不变
      • react:生成 .js 文件,并将 JSX 更改为等效的 React.createElement 调用

      例如

      🌐 For example

      这个示例代码:

      🌐 This sample code:

      tsx
      export const HelloWorld = () => <h1>Hello world</h1>;

      React: "react-jsx"[1]

      tsx
      import { jsx as _jsx } from "react/jsx-runtime";
      export const HelloWorld = () => _jsx("h1", { children: "Hello world" });
       
      Try

      React 开发转换:"react-jsxdev"[1]

      tsx
      import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
      const _jsxFileName = "/Users/q/code/nodejscn/typescript/src/packages/typescriptlang-org/index.tsx";
      export const HelloWorld = () => _jsxDEV("h1", { children: "Hello world" }, void 0, false, { fileName: _jsxFileName, lineNumber: 9, columnNumber: 33 }, this);
       
      Try

      保留:"preserve"

      🌐 Preserve: "preserve"

      tsx
      import React from 'react';
      export const HelloWorld = () => <h1>Hello world</h1>;
       
      Try

      React Native:"react-native"

      🌐 React Native: "react-native"

      tsx
      import React from 'react';
      export const HelloWorld = () => <h1>Hello world</h1>;
       
      Try

      旧版 React 运行时:"react"

      🌐 Legacy React runtime: "react"

      tsx
      import React from 'react';
      export const HelloWorld = () => React.createElement("h1", null, "Hello world");
       
      Try

      这个选项也可以通过使用 @jsxRuntime 注释按每个文件进行设置。

      🌐 This option can be used on a per-file basis too using an @jsxRuntime comment.

      始终为此文件使用经典运行时("react"):

      🌐 Always use the classic runtime ("react") for this file:

      tsx
      /* @jsxRuntime classic */
      export const HelloWorld = () => <h1>Hello world</h1>;

      始终为此文件使用自动运行时("react-jsx"):

      🌐 Always use the automatic runtime ("react-jsx") for this file:

      tsx
      /* @jsxRuntime automatic */
      export const HelloWorld = () => <h1>Hello world</h1>;

      # JSX 工厂 - jsxFactory

      在使用经典 JSX 运行时编译 JSX 元素时,更改 .js 文件中调用的函数。最常见的更改是如果使用 preact,使用 "h""preact.h" 而不是默认的 "React.createElement"

      🌐 Changes the function called in .js files when compiling JSX Elements using the classic JSX runtime. The most common change is to use "h" or "preact.h" instead of the default "React.createElement" if using preact.

      例如,这个 TSX 文件:

      🌐 For example, this TSX file:

      tsx
      import { h } from "preact";
      const HelloWorld = () => <div>Hello</div>;

      jsxFactory: "h" 看起来像这样:

      🌐 With jsxFactory: "h" looks like:

      tsx
      const preact_1 = require("preact");
      const HelloWorld = () => (0, preact_1.h)("div", null, "Hello");
       
      Try

      这个选项也可以按文件逐个使用,类似于Babel 的 /** @jsx h */ 指令

      🌐 This option can be used on a per-file basis too similar to Babel’s /** @jsx h */ directive.

      tsx
      /** @jsx h */
      import { h } from "preact";
      Cannot find module 'preact' or its corresponding type declarations.2307Cannot find module 'preact' or its corresponding type declarations.
       
      const HelloWorld = () => <div>Hello</div>;
      Try

      所选择的工厂还会影响在回退到全局命名空间之前,JSX 命名空间在何处被查找(用于类型检查信息)。

      🌐 The factory chosen will also affect where the JSX namespace is looked up (for type checking information) before falling back to the global one.

      如果工厂被定义为 React.createElement(默认值),编译器将在检查全局 JSX 之前检查 React.JSX。如果工厂被定义为 h,它将在检查全局 JSX 之前检查 h.JSX

      🌐 If the factory is defined as React.createElement (the default), the compiler will check for React.JSX before checking for a global JSX. If the factory is defined as h, it will check for h.JSX before a global JSX.

      # JSX 片段工厂 - jsxFragmentFactory

      当使用 jsxFactory 编译器选项针对 React JSX 输出时,指定要使用的 JSX 片段工厂函数,例如 Fragment

      🌐 Specify the JSX fragment factory function to use when targeting react JSX emit with jsxFactory compiler option is specified, e.g. Fragment.

      例如,使用此 TSConfig:

      🌐 For example with this TSConfig:

      {
      "": "esnext",
      "": "commonjs",
      "": "react",
      "": "h",
      "": "Fragment"
      }
      }

      这个 TSX 文件:

      🌐 This TSX file:

      tsx
      import { h, Fragment } from "preact";
      const HelloWorld = () => (
      <>
      <div>Hello</div>
      </>
      );

      将如下所示:

      🌐 Would look like:

      tsx
      const preact_1 = require("preact");
      const HelloWorld = () => ((0, preact_1.h)(preact_1.Fragment, null,
      (0, preact_1.h)("div", null, "Hello")));
       
      Try

      这个选项也可以针对每个文件使用,类似于Babel 的 /* @jsxFrag h */ 指令

      🌐 This option can be used on a per-file basis too similar to Babel’s /* @jsxFrag h */ directive.

      例如:

      🌐 For example:

      tsx
      /** @jsx h */
      /** @jsxFrag Fragment */
       
      import { h, Fragment } from "preact";
      Cannot find module 'preact' or its corresponding type declarations.2307Cannot find module 'preact' or its corresponding type declarations.
       
      const HelloWorld = () => (
      <>
      <div>Hello</div>
      </>
      );
      Try

      # JSX 导入源 - jsxImportSource

      声明在使用 jsx 作为 "react-jsx""react-jsxdev" 导入 jsxjsxs 工厂函数时要使用的模块说明符,这些在 TypeScript 4.1 中引入。

      🌐 Declares the module specifier to be used for importing the jsx and jsxs factory functions when using jsx as "react-jsx" or "react-jsxdev" which were introduced in TypeScript 4.1.

      React 17 中,该库通过单独的导入支持一种新的 JSX 转换形式。

      🌐 With React 17 the library supports a new form of JSX transformation via a separate import.

      例如,使用此代码:

      🌐 For example with this code:

      tsx
      import React from "react";
      function App() {
      return <h1>Hello World</h1>;
      }

      使用此 TSConfig:

      🌐 Using this TSConfig:

      {
      "": "esnext",
      "": "commonjs",
      "": "react-jsx"
      }
      }

      TypeScript 触发的 JavaScript 是:

      🌐 The emitted JavaScript from TypeScript is:

      tsx
      "use strict";
      Object.defineProperty(exports, "__esModule", { value: true });
      const jsx_runtime_1 = require("react/jsx-runtime");
      function App() {
      return (0, jsx_runtime_1.jsx)("h1", { children: "Hello World" });
      }
       
      Try

      例如,如果你想使用 "jsxImportSource": "preact",你需要一个像这样的 tsconfig:

      🌐 For example if you wanted to use "jsxImportSource": "preact", you need a tsconfig like:

      {
      "": "esnext",
      "": "commonjs",
      "": "react-jsx",
      "": "preact",
      "": ["preact"]
      }
      }

      将生成如下代码:

      🌐 Which generates code like:

      tsx
      function App() {
      return (0, jsx_runtime_1.jsx)("h1", { children: "Hello World" });
      }
       
      Try

      或者,你可以使用每个文件的指令来设置此选项,例如:

      🌐 Alternatively, you can use a per-file pragma to set this option, for example:

      tsx
      /** @jsxImportSource preact */
      export function App() {
      return <h1>Hello World</h1>;
      }

      会将 preact/jsx-runtime 添加为 _jsx 工厂的导入项。

      🌐 Would add preact/jsx-runtime as an import for the _jsx factory.

      注意:为了让它按预期工作,你的 tsx 文件必须包含 exportimport,这样它才会被视为一个模块。

      🌐 Note: In order for this to work like you would expect, your tsx file must include an export or import so that it is considered a module.

      # 库 - lib

      TypeScript 包含一组针对内置 JS API(如 Math)的默认类型定义,以及针对浏览器环境中可用内容(如 document)的类型定义。 TypeScript 还包含与你指定的 target 相匹配的新 JS 功能的 API;例如,如果 targetES6 或更高版本,则可以使用 Map 的定义。

      🌐 TypeScript includes a default set of type definitions for built-in JS APIs (like Math), as well as type definitions for things found in browser environments (like document). TypeScript also includes APIs for newer JS features matching the target you specify; for example the definition for Map is available if target is ES6 or newer.

      你可能出于以下几个原因想要更改这些:

      🌐 You may want to change these for a few reasons:

      • 你的程序不能在浏览器中运行,所以你不需要 "dom" 类型定义
      • 你的运行时平台提供了某些 JavaScript API 对象(可能通过 polyfill),但尚不支持给定 ECMAScript 版本的完整语法
      • 你拥有部分(但不是全部)更高级别 ECMAScript 版本的 polyfill 或原生实现

      在 TypeScript 4.5 中,lib 文件可以被 npm 模块覆盖,了解更多内容请查看 博客

      🌐 In TypeScript 4.5, lib files can be overridden by npm modules, find out more in the blog.

      高级库

      🌐 High Level libraries

      Name Contents
      ES5 Core definitions for all ES5 functionality
      ES2015 Additional APIs available in ES2015 (also known as ES6) - array.find, Promise, Proxy, Symbol, Map, Set, Reflect, etc.
      ES6 Alias for “ES2015”
      ES2016 Additional APIs available in ES2016 - array.include, etc.
      ES7 Alias for “ES2016”
      ES2017 Additional APIs available in ES2017 - Object.entries, Object.values, Atomics, SharedArrayBuffer, date.formatToParts, typed arrays, etc.
      ES2018 Additional APIs available in ES2018 - async iterables, promise.finally, Intl.PluralRules, regexp.groups, etc.
      ES2019 Additional APIs available in ES2019 - array.flat, array.flatMap, Object.fromEntries, string.trimStart, string.trimEnd, etc.
      ES2020 Additional APIs available in ES2020 - string.matchAll, etc.
      ES2021 Additional APIs available in ES2021 - promise.any, string.replaceAll etc.
      ES2022 Additional APIs available in ES2022 - array.at, RegExp.hasIndices, etc.
      ES2023 Additional APIs available in ES2023 - array.with, array.findLast, array.findLastIndex, array.toSorted, array.toReversed, etc.
      ESNext Additional APIs available in ESNext - This changes as the JavaScript specification evolves
      DOM DOM definitions - window, document, etc.
      WebWorker APIs available in WebWorker contexts
      ScriptHost APIs for the Windows Script Hosting System

      单个库组件

      🌐 Individual library components

      名字
      DOM.Iterable
      ES2015.Core
      ES2015.Collection
      ES2015.Generator
      ES2015.Iterable
      ES2015.Promise
      ES2015.Proxy
      ES2015.Reflect
      ES2015.Symbol
      ES2015.Symbol.WellKnown
      ES2016.Array.Include
      ES2017.object
      ES2017.Intl
      ES2017.SharedMemory
      ES2017.String
      ES2017.TypedArrays
      ES2018.Intl
      ES2018.Promise
      ES2018.RegExp
      ES2019.Array
      ES2019.Object
      ES2019.String
      ES2019.Symbol
      ES2020.String
      ES2020.Symbol.wellknown
      ES2021.Promise
      ES2021.String
      ES2021.WeakRef
      ESNext.AsyncIterable
      ESNext.Array
      ESNext.Intl
      ESNext.Symbol

      此列表可能已过时,你可以在 TypeScript 源代码 中查看完整列表。

      🌐 This list may be out of date, you can see the full list in the TypeScript source code.

      # 库替换 - libReplacement

      TypeScript 4.5 引入了用自定义文件替换默认 lib 文件的可能性。所有内置库文件首先会尝试从名为 @typescript/lib-* 的包中解析。例如,你可以使用以下 package.json 将你的 dom 库锁定到 the @types/web package 的特定版本:

      🌐 TypeScript 4.5 introduced the possibility of substituting the default lib files with custom ones. All built-in library files would first try to be resolved from packages named @typescript/lib-*. For example, you could lock your dom libraries onto a specific version of the @types/web package with the following package.json:

      json
      {
      "devDependencies": {
      "@typescript/lib-dom": "npm:@types/web@0.0.199"
      }
      }

      安装后,应存在一个名为 @typescript/lib-dom 的包,并且 TypeScript 在搜索 lib.dom.d.ts 时总是会在那里查找。

      🌐 When installed, a package called @typescript/lib-dom should exist, and TypeScript would always look there when searching for lib.dom.d.ts.

      --libReplacement 标志允许你禁用此行为。 如果你没有使用任何 @typescript/lib-* 包,现在可以使用 --libReplacement false 来禁用这些包的查找。 将来,--libReplacement false 可能会成为默认设置,因此如果你当前依赖这种行为,应该考虑使用 --libReplacement true 显式启用它。

      🌐 The --libReplacement flag allows you to disable this behavior. If you’re not using any @typescript/lib-* packages, you can now disable those package lookups with --libReplacement false. In the future, --libReplacement false may become the default, so if you currently rely on the behavior you should consider explicitly enabling it with --libReplacement true.

      • 默认:

        true

      # 模块检测 - moduleDetection

      此设置控制 TypeScript 如何确定文件是脚本还是模块

      🌐 This setting controls how TypeScript determines whether a file is a script or a module.

      有三个选择:

      🌐 There are three choices:

      • "auto"(默认)——TypeScript 不仅会查找 import 和 export 语句,还会在使用 modulenodenextnode16 运行时检查 package.json 中的 "type" 字段是否设置为 "module",并且在使用 jsxreact-jsx 运行时检查当前文件是否为 JSX 文件。
      • "legacy" - 与 4.6 及之前版本的行为相同,使用 import 和 export 语句来确定文件是否为模块。
      • "force" - 确保每个非声明文件都被视为模块。
      • 默认:

        "auto": Treat files with imports, exports, import.meta, jsx (with jsx: react-jsx), or esm format (with module: node16+) as modules.

      • 允许:
        • legacy

        • auto

        • force

      • 版本:

        4.7

      # 无库 - noLib

      禁用任何库文件的自动包含。 如果设置了此选项,将忽略 lib

      🌐 Disables the automatic inclusion of any library files. If this option is set, lib is ignored.

      TypeScript 在没有针对关键基本类型如 ArrayBooleanFunctionIArgumentsNumberObjectRegExpString 提供接口的情况下是无法编译任何内容的。预计如果你使用 noLib,你将需要自己提供这些类型的定义。

      🌐 TypeScript cannot compile anything without a set of interfaces for key primitives like: Array, Boolean, Function, IArguments, Number, Object, RegExp, and String. It is expected that if you use noLib you will be including your own type definitions for these.

      # React 命名空间 - reactNamespace

      改用 jsxFactory。在针对 TSX 文件的 react 时,指定调用 createElement 的对象。

      🌐 Use jsxFactory instead. Specify the object invoked for createElement when targeting react for TSX files.

      • 默认:

        React

      • 版本:

        1.8

      # 目标 - target

      现代浏览器支持所有 ES6 特性,所以 ES6 是一个不错的选择。如果你的代码要部署到较旧的环境,可以选择设置较低的目标;如果你的代码能够保证在较新的环境中运行,则可以选择较高的目标。

      🌐 Modern browsers support all ES6 features, so ES6 is a good choice. You might choose to set a lower target if your code is deployed to older environments, or a higher target if your code is guaranteed to run in newer environments.

      target 设置会改变哪些 JS 特性会被降级处理,哪些保持不变。例如,如果 target 是 ES5 或更低版本,箭头函数 () => this 会被转换成等效的 function 表达式。

      🌐 The target setting changes which JS features are downleveled and which are left intact. For example, an arrow function () => this will be turned into an equivalent function expression if target is ES5 or lower.

      更改 target 也会更改 lib 的默认值。你可以根据需要“混合搭配” targetlib 设置,但出于便利考虑,你也可以直接设置 target

      🌐 Changing target also changes the default value of lib. You may “mix and match” target and lib settings as desired, but you could just set target for convenience.

      对于像 Node 这样的开发者平台,有适用于 target 的基线,具体取决于平台类型及其版本。你可以在 tsconfig/bases 找到一套社区整理的 TSConfig,其中包括常见平台及其版本的配置。

      🌐 For developer platforms like Node there are baselines for the target, depending on the type of platform and its version. You can find a set of community organized TSConfigs at tsconfig/bases, which has configurations for common platforms and their versions.

      特殊的 ESNext 值指的是你的 TypeScript 版本所支持的最高版本。该设置应谨慎使用,因为它在不同的 TypeScript 版本之间的含义不同,并且可能会使升级变得不可预测。

      🌐 The special ESNext value refers to the highest version your version of TypeScript supports. This setting should be used with caution, since it doesn’t mean the same thing between different TypeScript versions and can make upgrades less predictable.

      • 默认:

        es2023 if module is node20; esnext if module is nodenext; ES5 otherwise.

      • 允许:
        • es3

        • es5

        • es6/es2015

        • es2016

        • es2017

        • es2018

        • es2019

        • es2020

        • es2021

        • es2022

        • es2023

        • es2024

        • esnext

      • 版本:

        1.0

      # 为类字段使用 Define - useDefineForClassFields

      这个标志用于迁移到即将发布的类字段标准版本。TypeScript 在 TC39 批准之前的很多年就引入了类字段。即将发布的规范的最新版本在运行时行为上与 TypeScript 的实现不同,但语法相同。

      🌐 This flag is used as part of migrating to the upcoming standard version of class fields. TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the upcoming specification has a different runtime behavior to TypeScript’s implementation but the same syntax.

      此标志切换到即将推出的 ECMA 运行时行为。

      🌐 This flag switches to the upcoming ECMA runtime behavior.

      你可以在3.7 版本说明中阅读有关此过渡的更多信息。

      🌐 You can read more about the transition in the 3.7 release notes.

      • 默认:

        true if target is ES2022 or higher, including ESNext; false otherwise.

      • 版本:

        3.7

      #编译器诊断

      # 诊断 - diagnostics

      用于输出调试的诊断信息。此命令是 extendedDiagnostics 的一个子集,后者提供的是更面向用户的结果,更易于理解。

      🌐 Used to output diagnostic information for debugging. This command is a subset of extendedDiagnostics which are more user-facing results, and easier to interpret.

      如果有 TypeScript 编译器工程师要求你在编译中使用这个标志来给出结果,那么使用 extendedDiagnostics 也是没有问题的。

      🌐 If you have been asked by a TypeScript compiler engineer to give the results using this flag in a compile, in which there is no harm in using extendedDiagnostics instead.

      # 解释文件 - explainFiles

      打印 TypeScript 视为项目一部分的文件的名称以及它们成为编译的一部分的原因。

      🌐 Print names of files which TypeScript sees as a part of your project and the reason they are part of the compilation.

      例如,在这个仅有一个 index.ts 文件的项目中

      🌐 For example, with this project of just a single index.ts file

      sh
      example
      ├── index.ts
      ├── package.json
      └── tsconfig.json

      使用 tsconfig.json 并将 explainFiles 设置为 true:

      🌐 Using a tsconfig.json which has explainFiles set to true:

      json
      {
      "compilerOptions": {
      "target": "es5",
      "module": "commonjs",
      "explainFiles": true
      }
      }

      针对此文件夹运行 TypeScript 将产生如下输出:

      🌐 Running TypeScript against this folder would have output like this:

      ❯ tsc
      node_modules/typescript/lib/lib.d.ts
      Default library for target 'es5'
      node_modules/typescript/lib/lib.es5.d.ts
      Library referenced via 'es5' from file 'node_modules/typescript/lib/lib.d.ts'
      node_modules/typescript/lib/lib.dom.d.ts
      Library referenced via 'dom' from file 'node_modules/typescript/lib/lib.d.ts'
      node_modules/typescript/lib/lib.webworker.importscripts.d.ts
      Library referenced via 'webworker.importscripts' from
      file 'node_modules/typescript/lib/lib.d.ts'
      node_modules/typescript/lib/lib.scripthost.d.ts
      Library referenced via 'scripthost'
      from file 'node_modules/typescript/lib/lib.d.ts'
      index.ts
      Matched by include pattern '**/*' in 'tsconfig.json'

      上面的输出显示:

      🌐 The output above show:

      • 初始的 lib.d.ts 查找基于 target,以及被引用的 .d.ts 文件链
      • 通过 include 的默认模式定位的 index.ts 文件

      此选项用于调试文件如何成为编译的一部分。

      🌐 This option is intended for debugging how a file has become a part of your compile.

      # 扩展诊断 - extendedDiagnostics

      你可以使用此标志来发现 TypeScript 在编译时花费时间的地方。这是一个用于了解你的代码库整体性能特性的工具。

      🌐 You can use this flag to discover where TypeScript is spending its time when compiling. This is a tool used for understanding the performance characteristics of your codebase overall.

      你可以在维基的性能部分了解更多关于如何衡量和理解输出的信息。

      🌐 You can learn more about how to measure and understand the output in the performance section of the wiki.

      # 生成 CPU 配置文件 - generateCpuProfile

      此选项让你有机会在编译器运行期间让 TypeScript 生成 v8 CPU 配置文件。CPU 配置文件可以帮助你了解构建速度慢的原因。

      🌐 This option gives you the chance to have TypeScript emit a v8 CPU profile during the compiler run. The CPU profile can provide insight into why your builds may be slow.

      此选项只能通过 CLI 使用:--generateCpuProfile tsc-output.cpuprofile

      🌐 This option can only be used from the CLI via: --generateCpuProfile tsc-output.cpuprofile.

      sh
      npm run tsc --generateCpuProfile tsc-output.cpuprofile

      此文件可以在基于 Chromium 的浏览器中打开,如 Chrome 或 Edge Developer,在 CPU 分析器 部分查看。你可以在 TypeScript 性能维基页面 中了解更多关于理解编译器性能的信息。

      🌐 This file can be opened in a chromium based browser like Chrome or Edge Developer in the CPU profiler section. You can learn more about understanding the compilers performance in the TypeScript wiki section on performance.

      • 默认:

        profile.cpuprofile

      • 版本:

        3.7

      # generateTrace - generateTrace

      生成事件跟踪和类型列表。

      🌐 Generates an event trace and a list of types.

      # 列出已生成的文件 - listEmittedFiles

      将编译生成的文件的一部分的名称打印到终端。

      🌐 Print names of generated files part of the compilation to the terminal.

      此标志在两种情况下很有用:

      🌐 This flag is useful in two cases:

      • 你希望将 TypeScript 作为终端中构建链的一部分进行转译,文件名将在下一个命令中处理。
      • 作为调试文件包含设置的一部分,你不确定 TypeScript 是否包含了你预期的文件。

      例如:

      🌐 For example:

      example
      ├── index.ts
      ├── package.json
      └── tsconfig.json

      使用:

      🌐 With:

      {
      "": true,
      }
      }

      将回显如下路径:

      🌐 Would echo paths like:

      $ npm run tsc
      path/to/example/index.js
      path/to/example/index.d.ts

      通常,TypeScript 会在成功时默默返回。

      🌐 Normally, TypeScript would return silently on success.

      # 列出文件 - listFiles

      打印编译中包含的文件名。当你不确定 TypeScript 是否包含了你期望的文件时,这非常有用。

      🌐 Print names of files part of the compilation. This is useful when you are not sure that TypeScript has included a file you expected.

      例如:

      🌐 For example:

      example
      ├── index.ts
      ├── package.json
      └── tsconfig.json

      使用:

      🌐 With:

      {
      "": true
      }
      }

      将回显如下路径:

      🌐 Would echo paths like:

      $ npm run tsc
      path/to/example/node_modules/typescript/lib/lib.d.ts
      path/to/example/node_modules/typescript/lib/lib.es5.d.ts
      path/to/example/node_modules/typescript/lib/lib.dom.d.ts
      path/to/example/node_modules/typescript/lib/lib.webworker.importscripts.d.ts
      path/to/example/node_modules/typescript/lib/lib.scripthost.d.ts
      path/to/example/index.ts

      注意,如果使用 TypeScript 4.2,建议使用 explainFiles,它还提供了为什么添加该文件的解释。

      🌐 Note if using TypeScript 4.2, prefer explainFiles which offers an explanation of why a file was added too.

      # noCheck - noCheck

      禁用完整类型检查(仅报告关键解析和触发错误)。

      🌐 Disable full type checking (only critical parse and emit errors will be reported).

      # 跟踪分辨率 - traceResolution

      当你试图调试为什么一个模块没有被包含时。 你可以将 traceResolution 设置为 true,让 TypeScript 打印它在处理每个文件时的解析过程信息。

      🌐 When you are trying to debug why a module isn’t being included. You can set traceResolution to true to have TypeScript print information about its resolution process for each processed file.

      #项目

      # 复合材料 - composite

      composite 选项强制执行某些约束,这使得构建工具(包括 TypeScript 本身,在 --build 模式下)能够快速判断项目是否已经构建完成。

      🌐 The composite option enforces certain constraints which make it possible for build tools (including TypeScript itself, under --build mode) to quickly determine if a project has been built yet.

      启用此设置时:

      🌐 When this setting is on:

      • [rootDir](#rootDir) 设置,如果没有显式设置,默认指向包含 tsconfig.json 文件的目录。
      • 所有实现文件必须符合 include 模式或列在 files 数组中。如果违反此约束,tsc 会告诉你哪些文件未被指定。
      • declaration 默认值为 true

      你可以在手册中找到关于 TypeScript 项目的文档。

      🌐 You can find documentation on TypeScript projects in the handbook.

      # 禁用引用项目加载 - disableReferencedProjectLoad

      在多项目 TypeScript 程序中,TypeScript 会将所有可用的项目加载到内存中,以便为需要完整知识图的编辑器响应(如“查找所有引用”)提供准确的结果。

      🌐 In multi-project TypeScript programs, TypeScript will load all of the available projects into memory in order to provide accurate results for editor responses which require a full knowledge graph like ‘Find All References’.

      如果你的项目很大,你可以使用标志 disableReferencedProjectLoad 来禁用所有项目的自动加载。相反,项目会在你通过编辑器打开文件时动态加载。

      🌐 If your project is large, you can use the flag disableReferencedProjectLoad to disable the automatic loading of all projects. Instead, projects are loaded dynamically as you open files through your editor.

      # 禁用解决方案搜索 - disableSolutionSearching

      在使用复合 TypeScript 项目时,此选项提供了一种声明的方法,即你不希望在使用编辑器中的“查找所有引用”或“跳转到定义”等功能时包含某个项目。

      🌐 When working with composite TypeScript projects, this option provides a way to declare that you do not want a project to be included when using features like find all references or jump to definition in an editor.

      你可以使用此标志来提高大型复合项目的响应能力。

      🌐 This flag is something you can use to increase responsiveness in large composite projects.

      # 禁用源项目引用重定向 - disableSourceOfProjectReferenceRedirect

      在处理复合 TypeScript 项目时,此选项提供了一种方法,可以回到3.7 之前的行为,即使用 d.ts 文件作为模块之间的边界。在 3.7 中,真实来源现在是你的 TypeScript 文件。

      🌐 When working with composite TypeScript projects, this option provides a way to go back to the pre-3.7 behavior where d.ts files were used to as the boundaries between modules. In 3.7 the source of truth is now your TypeScript files.

      # 渐进的 - incremental

      指示 TypeScript 将上一次编译的项目图信息保存到存储在磁盘上的文件中。这会在与编译输出相同的文件夹中创建一系列 .tsbuildinfo 文件。它们在运行时不会被你的 JavaScript 使用,可以安全删除。你可以在 3.4 版本说明 中查看更多关于该标志的信息。

      🌐 Tells TypeScript to save information about the project graph from the last compilation to files stored on disk. This creates a series of .tsbuildinfo files in the same folder as your compilation output. They are not used by your JavaScript at runtime and can be safely deleted. You can read more about the flag in the 3.4 release notes.

      要控制要构建文件的文件夹,请使用配置选项 tsBuildInfoFile

      🌐 To control which folders you want to the files to be built to, use the config option tsBuildInfoFile.

      # TS 构建信息文件 - tsBuildInfoFile

      此设置允许你指定一个文件,用于存储增量编译信息,作为复合项目的一部分,从而加快大型 TypeScript 代码库的构建速度。你可以在手册中了解有关复合项目的更多信息。

      🌐 This setting lets you specify a file for storing incremental compilation information as a part of composite projects which enables faster building of larger TypeScript codebases. You can read more about composite projects in the handbook.

      默认值取决于其他设置的组合:

      🌐 The default depends on a combination of other settings:

      • 如果设置了 outFile,默认值为 <outFile>.tsbuildinfo
      • 如果设置了 rootDiroutDir,那么文件就是 <outDir>/<relative path to config from rootDir>/<config name>.tsbuildinfo。例如,如果 rootDirsrcoutDirdest,且配置为 ./tsconfig.json,那么默认值就是 ./tsconfig.tsbuildinfo,因为从 src/./tsconfig.json 的相对路径是 ../
      • 如果设置了 outDir,那么默认值是 <outDir>/<config name>.tsbuildInfo
      • 否则,默认是 <config name>.tsbuildInfo

      #输出格式

      # 无错误截断 - noErrorTruncation

      不要截断错误消息。

      🌐 Do not truncate error messages.

      使用 false,默认值。

      🌐 With false, the default.

      ts
      var x: {
      propertyWithAnExceedinglyLongName1: string;
      propertyWithAnExceedinglyLongName2: string;
      propertyWithAnExceedinglyLongName3: string;
      propertyWithAnExceedinglyLongName4: string;
      propertyWithAnExceedinglyLongName5: string;
      propertyWithAnExceedinglyLongName6: string;
      propertyWithAnExceedinglyLongName7: string;
      propertyWithAnExceedinglyLongName8: string;
      };
       
      // String representation of type of 'x' should be truncated in error message
      var s: string = x;
      Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propertyWithAnExceedinglyLongName3: string; propertyWithAnExceedinglyLongName4: string; propertyWithAnExceedinglyLongName5: string; propertyWithAnExceedinglyLongName6: string; propertyWithAnExceedinglyLongName7: string; propert...' is not assignable to type 'string'.
      Variable 'x' is used before being assigned.
      2322
      2454
      Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propertyWithAnExceedinglyLongName3: string; propertyWithAnExceedinglyLongName4: string; propertyWithAnExceedinglyLongName5: string; propertyWithAnExceedinglyLongName6: string; propertyWithAnExceedinglyLongName7: string; propert...' is not assignable to type 'string'.
      Variable 'x' is used before being assigned.
      Try

      使用 true

      🌐 With true

      ts
      var x: {
      propertyWithAnExceedinglyLongName1: string;
      propertyWithAnExceedinglyLongName2: string;
      propertyWithAnExceedinglyLongName3: string;
      propertyWithAnExceedinglyLongName4: string;
      propertyWithAnExceedinglyLongName5: string;
      propertyWithAnExceedinglyLongName6: string;
      propertyWithAnExceedinglyLongName7: string;
      propertyWithAnExceedinglyLongName8: string;
      };
       
      // String representation of type of 'x' should be truncated in error message
      var s: string = x;
      Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propertyWithAnExceedinglyLongName3: string; propertyWithAnExceedinglyLongName4: string; propertyWithAnExceedinglyLongName5: string; propertyWithAnExceedinglyLongName6: string; propertyWithAnExceedinglyLongName7: string; propertyWithAnExceedinglyLongName8: string; }' is not assignable to type 'string'.
      Variable 'x' is used before being assigned.
      2322
      2454
      Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propertyWithAnExceedinglyLongName3: string; propertyWithAnExceedinglyLongName4: string; propertyWithAnExceedinglyLongName5: string; propertyWithAnExceedinglyLongName6: string; propertyWithAnExceedinglyLongName7: string; propertyWithAnExceedinglyLongName8: string; }' is not assignable to type 'string'.
      Variable 'x' is used before being assigned.
      Try

      # 保存监控输出 - preserveWatchOutput

      是否在监视模式下保留过时的控制台输出,而不是每次发生更改时清除屏幕。

      🌐 Whether to keep outdated console output in watch mode instead of clearing the screen every time a change happened.

      • 内部
      • 版本:

        2.8

      # 漂亮 - pretty

      使用颜色和上下文来美化错误和信息,这默认是开启的 —— 这样可以让编译器的信息不那么简短单一,更加丰富多彩。

      🌐 Stylize errors and messages using color and context, this is on by default — offers you a chance to have less terse, single colored messages from the compiler.

      • 默认:

        true

      • 版本:

        1.8

      #完整性

      # 跳过默认库检查 - skipDefaultLibCheck

      请改用 skipLibCheck。跳过默认库声明文件的类型检查。

      🌐 Use skipLibCheck instead. Skip type checking of default library declaration files.

      # 跳过库检查 - skipLibCheck

      跳过声明文件的类型检查。

      🌐 Skip type checking of declaration files.

      这可以在牺牲类型系统准确性的情况下节省编译时间。例如,两个库可能会以不一致的方式定义相同的 type 的两个副本。TypeScript 不会对所有 d.ts 文件进行完整检查,而只会对你在应用源代码中明确引用的代码进行类型检查。

      🌐 This can save time during compilation at the expense of type-system accuracy. For example, two libraries could define two copies of the same type in an inconsistent way. Rather than doing a full check of all d.ts files, TypeScript will type check the code you specifically refer to in your app’s source code.

      一个你可能会考虑使用 skipLibCheck 的常见情况是当你的 node_modules 中有两个库类型的副本。在这些情况下,你应该考虑使用像 yarn 的 resolutions 这样的功能,以确保你的依赖树中只有一个该依赖的副本,或者通过理解依赖解析的方式来确保只有一个副本,从而在不使用额外工具的情况下解决问题。

      🌐 A common case where you might think to use skipLibCheck is when there are two copies of a library’s types in your node_modules. In these cases, you should consider using a feature like yarn’s resolutions to ensure there is only one copy of that dependency in your tree or investigate how to ensure there is only one copy by understanding the dependency resolution to fix the issue without additional tooling.

      另一种可能性是,当你在 TypeScript 版本之间迁移时,更改会导致 node_modules 和 JS 标准库出现故障,而你不想在 TypeScript 更新期间处理这些故障。

      🌐 Another possibility is when you are migrating between TypeScript releases and the changes cause breakages in node_modules and the JS standard libraries which you do not want to deal with during the TypeScript update.

      注意,如果这些问题来自 TypeScript 标准库,你可以使用 TypeScript 4.5 的库替换 技术来替换该库。

      🌐 Note, that if these issues come from the TypeScript standard library you can replace the library using TypeScript 4.5’s lib replacement technique.

      • 推荐
      • 版本:

        2.0

      #命令行

      #监视选项

      TypeScript 3.8 推出了一种新的目录监视策略,这对于高效捕捉 node_modules 的变化至关重要。

      🌐 TypeScript 3.8 shipped a new strategy for watching directories, which is crucial for efficiently picking up changes to node_modules.

      在像 Linux 这样的操作系统上,TypeScript 会在 node_modules 及其许多子目录中安装目录监视器(而不是文件监视器)来检测依赖的更改。这是因为可用的文件监视器数量通常远小于 node_modules 中的文件数量,而需要跟踪的目录则少得多。

      🌐 On operating systems like Linux, TypeScript installs directory watchers (as opposed to file watchers) on node_modules and many of its subdirectories to detect changes in dependencies. This is because the number of available file watchers is often eclipsed by the number of files in node_modules, whereas there are way fewer directories to track.

      因为每个项目在不同策略下可能表现更好,而这种新方法可能不适合你的工作流程,TypeScript 3.8 引入了一个新的 watchOptions 字段,允许用户告诉编译器/语言服务应该使用哪种监视策略来跟踪文件和目录。

      🌐 Because every project might work better under different strategies, and this new approach might not work well for your workflows, TypeScript 3.8 introduces a new watchOptions field which allows users to tell the compiler/language service which watching strategies should be used to keep track of files and directories.

      # 假设更改仅影响直接依赖 - assumeChangesOnlyAffectDirectDependencies

      启用此选项后,TypeScript 将避免重新检查/重建所有真正可能受影响的文件,而仅重新检查/重建已更改的文件以及直接导入它们的文件。

      🌐 When this option is enabled, TypeScript will avoid rechecking/rebuilding all truly possibly-affected files, and only recheck/rebuild files that have changed as well as files that directly import them.

      这可以被认为是观察算法的一种“快速且随意”的实现,它可以大幅减少增量重建时间,但代价是需要偶尔运行完整构建以获取所有编译器错误信息。

      🌐 This can be considered a ‘fast & loose’ implementation of the watching algorithm, which can drastically reduce incremental rebuild times at the expense of having to run the full build occasionally to get all compiler error messages.

      监视选项

      🌐 Watch Options

      你可以配置 TypeScript --watch 的工作方式。本节主要用于处理 fs.watchfs.watchFile 有额外限制的情况,例如在 Linux 上。你可以在 配置 Watch 中了解更多信息。

      🌐 You can configure the how TypeScript --watch works. This section is mainly for handling case where fs.watch and fs.watchFile have additional constraints like on Linux. You can read more at Configuring Watch.

      # 监视文件 - watchFile

      监视单个文件的策略。

      🌐 The strategy for how individual files are watched.

      • fixedPollingInterval:以固定间隔每秒检查每个文件是否有更改。
      • priorityPollingInterval:每秒检查每个文件是否有更改,但使用启发式方法检查某些类型的文件的频率要低于其他文件。
      • dynamicPriorityPolling:使用动态队列,其中修改频率较低的文件将较少被检查。
      • useFsEvents(默认):尝试使用操作系统/文件系统的本地事件来监控文件变化。
      • useFsEventsOnParentDirectory:尝试使用操作系统/文件系统的原生事件来监听文件父目录的更改
      • 允许:
        • fixedpollinginterval

        • prioritypollinginterval

        • dynamicprioritypolling

        • fixedchunksizepolling

        • usefsevents

        • usefseventsonparentdirectory

      • 版本:

        3.8

      # 监视目录 - watchDirectory

      在缺乏递归文件监视功能的系统下监视整个目录树的策略。

      🌐 The strategy for how entire directory trees are watched under systems that lack recursive file-watching functionality.

      • fixedPollingInterval:以固定间隔每秒检查每个目录是否有更改。
      • dynamicPriorityPolling:使用动态队列,其中修改频率较低的目录将较少被检查。
      • useFsEvents(默认):尝试使用操作系统/文件系统的本地事件来监视目录变化。
      • 允许:
        • usefsevents

        • fixedpollinginterval

        • dynamicprioritypolling

        • fixedchunksizepolling

      • 版本:

        3.8

      # 备用轮询 - fallbackPolling

      使用文件系统事件时,此选项指定在系统用尽原生文件监视器和/或不支持原生文件监视器时使用的轮询策略。

      🌐 When using file system events, this option specifies the polling strategy that gets used when the system runs out of native file watchers and/or doesn’t support native file watchers.

      • fixedPollingInterval:以固定间隔每秒检查每个文件是否有更改。
      • priorityPollingInterval:每秒检查每个文件是否有更改,但使用启发式方法检查某些类型的文件的频率要低于其他文件。
      • dynamicPriorityPolling:使用动态队列,其中修改频率较低的文件将较少被检查。
      • synchronousWatchDirectory:禁用目录的延迟监控。延迟监控在大量文件可能同时发生变化时很有用(例如,通过运行 npm install 导致 node_modules 的变化),但在一些不常见的配置下,你可能希望使用此标志将其禁用。
      • 允许:
        • fixedinterval

        • priorityinterval

        • dynamicpriority

        • fixedchunksize

      • 版本:

        3.8

      # 同步监视目录 - synchronousWatchDirectory

      在不原生支持递归监视的平台上,同步调用回调并更新目录监视器的状态,而不是设置一个很短的超时以允许文件上可能发生的多次修改。

      🌐 Synchronously call callbacks and update the state of directory watchers on platforms that don`t support recursive watching natively. Instead of giving a small timeout to allow for potentially multiple edits to occur on a file.

      {
      "watchOptions": {
      }
      }

      # 排除目录 - excludeDirectories

      你可以使用 excludeFiles 来大幅减少在 --watch 期间被监视的文件数量。这是减少 TypeScript 在 Linux 上跟踪的打开文件数量的一个有用方法。

      🌐 You can use excludeFiles to drastically reduce the number of files which are watched during --watch. This can be a useful way to reduce the number of open file which TypeScript tracks on Linux.

      {
      "watchOptions": {
      "": ["**/node_modules", "_build", "temp/*"]
      }
      }

      # 排除文件 - excludeFiles

      你可以使用 excludeFiles 从被监视的文件中移除一组特定的文件。

      🌐 You can use excludeFiles to remove a set of specific files from the files which are watched.

      {
      "watchOptions": {
      "": ["temp/file.ts"]
      }
      }

      类型获取

      🌐 Type Acquisition

      类型获取对于 JavaScript 项目来说是重要的。在 TypeScript 项目中,你需要在项目中显式地包含类型。然而,对于 JavaScript 项目,TypeScript 工具会在后台为你的模块下载类型,并且这些类型会存放在 node_modules 文件夹之外。

      🌐 Type Acquisition is only important for JavaScript projects. In TypeScript projects you need to include the types in your projects explicitly. However, for JavaScript projects, the TypeScript tooling will download types for your modules in the background and outside of your node_modules folder.

      # 启用 - enable

      禁用 JavaScript 项目中的自动类型获取:

      🌐 Disables automatic type acquisition in JavaScript projects:

      json
      {
      "typeAcquisition": {
      "enable": false
      }
      }

        # 包含 - include

        如果你有一个 JavaScript 项目,其中 TypeScript 需要额外的指导来理解全局依赖,或者通过 disableFilenameBasedTypeAcquisition 禁用了内置推断。

        🌐 If you have a JavaScript project where TypeScript needs additional guidance to understand global dependencies, or have disabled the built-in inference via disableFilenameBasedTypeAcquisition.

        你可以使用 include 来指定应该从 DefinitelyTyped 使用哪些类型:

        🌐 You can use include to specify which types should be used from DefinitelyTyped:

        json
        {
        "typeAcquisition": {
        "include": ["jquery"]
        }
        }

        # 排除 - exclude

        提供了一个配置,用于在 JavaScript 项目中禁用某个模块的类型获取。这对于在测试基础设施中包含其他库,但在主应用中不需要的项目非常有用。

        🌐 Offers a config for disabling the type-acquisition for a certain module in JavaScript projects. This can be useful for projects which include other libraries in testing infrastructure which aren’t needed in the main application.

        json
        {
        "typeAcquisition": {
        "exclude": ["jest", "mocha"]
        }
        }

        # 禁用基于文件名的类型获取 - disableFilenameBasedTypeAcquisition

        TypeScript 的类型获取可以根据项目中的文件名推断应该添加哪些类型。这意味着在你的项目中有一个像 jquery.js 的文件时,会自动从 DefinitelyTyped 下载 JQuery 的类型。

        🌐 TypeScript’s type acquisition can infer what types should be added based on filenames in a project. This means that having a file like jquery.js in your project would automatically download the types for JQuery from DefinitelyTyped.

        你可以通过 disableFilenameBasedTypeAcquisition 来禁用它。

        🌐 You can disable this via disableFilenameBasedTypeAcquisition.

        json
        {
        "typeAcquisition": {
        "disableFilenameBasedTypeAcquisition": true
        }
        }