tsconfig 最新の共通設定マニュアル【随時更新】

TypeScript 構成ファイル (tsconfig.json) は、TypeScript プロジェクトを構成するための重要なファイルです。これにより、開発者は TypeScript コンパイラーの動作をカスタマイズし、コンパイル オプション、ファイルの包含および除外ルール、出力ディレクトリなどを指定できます。tsconfig.json を適切に構成することで、プロジェクトの要件に応じて柔軟な TypeScript のコンパイル設定を行うことができます。

この記事では、tsconfig.json のさまざまな構成オプションを包括的に説明し、いくつかの一般的な使用シナリオとサンプル コードを提供します。

共通オプションの概要

{
  "compilerOptions": {

    /* 基本选项 */
    "target": "es5", // 生成代码的 ECMAScript 目标版本
    "module": "commonjs", // 生成代码的模块标准
    "lib": ["es6", "dom"], // 编译过程中需要引入的库文件的列表
    "allowJs": true, // 是否编译 JS 文件
    "checkJs": true, // 是否在 JS 文件中报告错误
    "jsx": "preserve", // 在 .tsx 文件里支持 JSX: 'preserve', 'react-native', or 'react'
    "declaration": true, // 是否生成 .d.ts 类型定义文件
    "emitDeclarationOnly": true, // 只生成类型声明文件,不生成js
    "declarationMap": true, // 为每个 .d.ts 文件生成 sourcemap
    "sourceMap": true, // 是否生成 .map 文件
    "outFile": "./dist/main.js", // 将输出文件合并为一个文件
    "outDir": "./dist", // 输出文件夹
    "rootDir": "./", // 输入文件 folder 路径
    "composite": true, // 是否编译构建引用项目
    "removeComments": true, // 删除注释
    "noEmit": true, // 不输出文件
    "importHelpers": true, // 通过 tslib 引入辅助工具函数
    "downlevelIteration": true, // 降级遍历器实现的支持
    "useDefineForClassFields": true, // 是否使用 Object.defineProperty 定义类实例属性

    /* 严格的类型检查 */
    "strict": true, // 启用所有严格类型检查
    "noImplicitAny": true, // 不允许隐式的 any 类型
    "strictNullChecks": true, // 不允许把 null、undefined 赋值给其他类型变量
    "strictFunctionTypes": true, // 严格检查函数的类型
    "strictBindCallApply": true, // 严格检查 bind、call 和 apply 的参数规则
    "strictPropertyInitialization": true, // 类的实例属性必须初始化
    "noImplicitThis": true, // 不允许 this 有隐式的 any类型

    /* 额外检查 */  
    "noUnusedLocals": true, // 检查未使用的局部变量
    "noUnusedParameters": true, // 检查未使用的参数
    "noImplicitReturns": true, // 每个分支都会有返回值
    "noFallthroughCasesInSwitch": true, // 检查 switch 语句包含正确的 break

    /* 模块解析 */
    "isolatedModules": true, // 控制是否将每个文件作为单独的模块处理。
    "moduleResolution": "node", // 模块解析策略
    "allowImportingTsExtensions": true, // 允许从没有默认导出的模块中导入类型定义(.d.ts)文件
    "baseUrl": "./", // 解析非相对模块的基地址
    "paths": {}, // 模块名称到基于 baseUrl 的路径映射表
    "rootDirs": [], // 将多个文件夹放在一个虚拟目录下
    "typeRoots": [], // 声明文件目录列表
    "types": [], // 需要包含的类型声明文件名列表
    "allowSyntheticDefaultImports": true, // 允许从没有默认导出的模块默认导入
    "esModuleInterop": true, // 通过创建命名空间实现 CommonJS 兼容性
    "resolveJsonModule": true, // 自动解析JSON文件

    /* Source Map */
    "sourceRoot": "", // TypeScript 源代码所在的目录
    "mapRoot": "", // 指定 map 文件的路径
    "inlineSourceMap": true, // 生成单个 sourcemaps 文件,而不是将 sourcemaps 生成不同的文件
    "inlineSources": true, // 将代码与 sourcemaps 生成到一个文件中

    /* 实验性 */ 
    "experimentalDecorators": true, // 启用实验性的装饰器特性
    "emitDecoratorMetadata": true // 为装饰器提供元数据支持
  },

    "files": [], // files可以配置一个数组列表,里面包含指定文件的相对或绝对路径,编译器在编译的时候只会编译包含在files中列出的文件,如果不指定,则取决于有没有设置include选项,如果没有include选项,则默认会编译根目录以及所有子目录中的文件。这里列出的路径必须是指定文件,而不是某个文件夹,而且不能使用* ? **/ 等通配符 
    "include": [], // include也可以指定要编译的路径列表,但是和files的区别在于,这里的路径可以是文件夹,也可以是文件,可以使用相对和绝对路径,而且可以使用通配符,比如"./src"即表示要编译src文件夹下的所有文件以及子文件夹的文件 
    "exclude": [], // exclude表示要排除的、不编译的文件,它也可以指定一个列表,规则和include一样,可以是文件或文件夹,可以是相对路径或绝对路径,可以使用通配符 
    "extends": "", // extends可以通过指定一个其他的tsconfig.json文件路径,来继承这个配置文件里的配置,继承来的文件的配置会覆盖当前文件定义的配置。TS在3.2版本开始,支持继承一个来自Node.js包的tsconfig.json配置文件 
    "compileOnSave": true, // compileOnSave的值是true或false,如果设为true,在我们编辑了项目中的文件保存的时候,编辑器会根据tsconfig.json中的配置重新生成文件,不过这个要编辑器支持 
    "references": [], // 一个对象数组,指定要引用的项目
}

一般的なオプションの分析

useDefineForClassFields

useDefineForClassFields は TypeScript のコンパイル オプションで、クラスのインスタンス プロパティのコンパイル方法を制御するために使用されます。

このオプションの機能は次のとおりです。

  • true に設定すると、クラスのインスタンス プロパティがコンパイルされ、Object.defineProperty を使用して定義されます。
  • false (デフォルト) に設定すると、クラスのインスタンス プロパティは定義への単純な割り当てにコンパイルされます。

例えば:

class Foo {
  bar = 123; 
}

useDefineForClassFields が true の場合:


var Foo = class {
  constructor() {
    Object.defineProperty(this, "bar", {
      configurable: true,
      writable: true,
      value: 123
    });
  }
}

useDefineForClassFields が false (デフォルト) の場合:

var Foo = class {
  constructor() {
    this.bar = 123; 
  }
}

useDefineForClassFields は、クラス フィールド宣言の構成オプションです。TypeScript バージョン 2.7 で導入され、後続のバージョンでは改良および最適化されています。

useDefineForClassFields オプションをオンにすると、クラス フィールドの宣言方法が次のように変更されます。

// 开启 useDefineForClassFields
class MyClass {
  myField = 42;
}

// 等价于未开启 useDefineForClassFields
class MyClass {
  constructor() {
    this.myField = 42;
  }
}

useDefineForClassFields オプションが有効になっていない場合、通常、クラス フィールドの初期化をコンストラクターに配置する必要があります。このオプションをオンにすると、コンストラクターで代入ステートメントを使用する場合と同様に、クラス定義で初期化を直接実行できます。

useDefineForClassFields を有効にする利点は次のとおりです。

  1. 簡潔さ: コードがより簡潔になり、読みやすくなりました。コンストラクターでクラス フィールドを手動で初期化する必要がなくなり、コードがより簡潔になりました。
  2. 読みやすさ: クラス定義でフィールドを直接初期化することで、フィールドの初期値がより明確に確認できるようになり、コードの読みやすさが向上します。
  3. 类字段支持类型推断:开启该选项后,TypeScript 可以正确推断类字段的类型,不再需要显式地指定类型。

在 Vite v2.5.0 及更高版本中,如果 TypeScript 的 target 是 ESNext,则此选项的默认值为 true。这与 tsc v4.3.2 及更高版本的行为一致。这也是标准 ECMAScript 的运行时行为

isolatedModules

控制是否将每个文件作为单独的模块处理。

默认情况下,该选项为 true。这意味着:

  • 每个文件都作为单独的模块处理。
  • 文件之间的变量、函数、类等不会相互影响。
  • 文件只能访问自己导出的内容。

如果设置为 false:

  • 整个项目的文件会合并成一个模块。
  • 文件之间可以相互访问变量、函数、类等成员。
  • 一个文件可以直接使用另一个文件暴露出来的内容。

通常我们希望每个文件是独立的模块,所以保持该选项为 true。

但是有些场景下需要关闭该选项:

  • 当项目文件间有重名的类时,需要设置为 false 以便合并为一个类。
  • 当不同文件需要共享某些变量或状态时,需要设置为 false。

总之,isolatedModules 用于控制文件之间是否独立。它可以处理一些特殊的场景,但通常保持 true 即可。

paths

paths 选项用于配置模块导入时的路径映射。通过使用 paths,你可以在项目中定义模块的别名,使得导入模块时可以使用这些别名,从而简化代码,减少路径错误,并提高可维护性。

以下是 paths 选项的使用示例:

  1. 假设你的项目目录结构如下:
project
|-- src
|   |-- components
|   |   |-- Button.ts
|   |   |-- Card.ts
|   |-- utils
|   |   |-- helpers.ts
|-- tsconfig.json
  1. 在 tsconfig.json 文件中,你可以这样配置 paths 选项:
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@components/*": ["components/*"],
      "@utils/*": ["utils/*"]
    }
  }
}

在这个例子中:

  • "baseUrl": "./src" 表示项目中所有导入模块的相对路径都是相对于 "src" 目录的。

  • "paths" 配置了两个路径映射:

    • "@components/*" 是一个模块别名,它将匹配任何以 "@components/" 开头的导入路径。
    • "@utils/*" 是另一个模块别名,它将匹配任何以 "@utils/" 开头的导入路径。
  1. 使用别名进行模块导入:

现在,你可以在你的代码中使用这些别名进行模块导入,而不需要使用相对路径或绝对路径。

// 使用别名导入模块
import { Button } from "@components/Button";
import { Card } from "@components/Card";
import { someHelperFunction } from "@utils/helpers";

// 使用别名进行导入后的代码更加简洁

通过使用 paths 选项,你可以定义更多的模块别名,根据你的项目结构和需求来简化导入语句,提高代码的可读性和可维护性

baseUrl

用于指定 TypeScript 编译器在解析模块导入路径时的基础路径。通过设置 baseUrl,你可以简化模块导入语句,使得导入模块时的路径更加清晰和简洁。

假设项目结构如下:

project
|-- src
|   |-- components
|   |   |-- Button.ts
|   |   |-- Card.ts
|   |-- utils
|   |   |-- helpers.ts
|-- tsconfig.json

默认情况下,TypeScript 编译器会将所有导入语句视为相对于包含它们的文件的路径。这意味着,如果你在 Button.ts 中想导入 Card.ts,通常需要使用相对路径来完成导入,例如:

import { Card } from '../Card';

但是,随着项目规模增长,导入语句中的相对路径可能会变得非常复杂和深层嵌套,这可能导致代码可读性降低,维护困难。

为了解决这个问题,可以使用 baseUrl 选项,将模块导入路径的基础路径设置为项目中的某个目录,通常是项目的 src 目录。

在 tsconfig.json 文件中设置 baseUrl 的用法如下:

{
  "compilerOptions": {
    "baseUrl": "./src"
  }
}

上面的配置将 baseUrl 设置为项目中的 src 目录。这意味着,在所有的模块导入语句中,TypeScript 编译器会将导入路径解析为相对于 ./src 目录的路径。因此,我们可以简化模块导入语句,如下所示:

// 使用 baseUrl 后,导入语句更简洁
import { Card } from 'components/Card';
import { someHelperFunction } from 'utils/helpers';

通过设置 baseUrl 选项,简化模块导入语句,提高代码的可读性和可维护性,尤其在大型项目中,这个功能尤为有用。

skipLibCheck

用于控制是否在编译时跳过对声明文件(.d.ts 文件)的类型检查。

在 TypeScript 项目中,除了普通的 TypeScript 文件外,我们还可能会引入第三方库或其他模块,这些模块通常会伴随着对应的声明文件,以便 TypeScript 在编译时能够正确地识别这些库的类型信息。有时候这些声明文件可能并不完善或存在一些错误,导致 TypeScript 编译器在检查时会发出一些类型相关的警告或错误。

开启 skipLibCheck 选项会提高编译速度但是可能会导致一些类型相关的问题在运行时才暴露出来,

moduleResolution

moduleResolution 选项用于配置模块解析策略,它有以下可选值:

  1. "node": 使用Node.js的模块解析策略。这是默认值。
  2. "classic": 使用TypeScript早期的模块解析策略,已废弃。
  3. "bundler": TypeScript在版本4.5中新增的一个模块解析策略。

"bundler"策略在解析模块时,会模拟一个 bundler 的行为。

它与"node"策略的主要区别是:

  • "node"会将文件和目录作为不同的模块解析。
  • "bundler"会将文件和目录都合并解析为一个模块。

举例来说,对于导入路径 "./foo":

  • "node"会先查找 ./foo.ts 文件,如果不存在再查找 ./foo/index.ts
  • "bundler"会直接将 ./foo.ts 和 ./foo/index.ts 合并为一个模块

使用"bundler"策略的目的是为了使TypeScript模块解析更接近捆绑工具(webpack等)的解析策略。

它的常见使用场景包括:

  • 使用webpack等bundler时,让TypeScript的模块解析方式与之匹配,编写代码时能获得一致的导入解析结果。
  • 需要模块路径映射等高级功能时,使用bundler策略可以避免与TypeScript解析不一致的情况。
  • 希望模块解析更加灵活,文件和目录可以混合导入时。

allowImportingTsExtensions

通常情况下,如果一个模块没有默认导出,那么只能导入该模块中的类型,不能导入它的类型定义文件。

举例来说,存在一个没有默认导出的模块:

// utils.ts
export function util1() {}

对应的类型定义文件:

// utils.d.ts 
export function util2();

默认情况下,不能导入 utils.d.ts 中的类型:

// index.ts
import { util2 } from './utils.d.ts'; // Error

但如果设置了allowImportingTsExtensions为true,则可以导入:

{
  "compilerOptions": {
    "allowImportingTsExtensions": true
  } 
}

// index.ts
import { util2 } } from './utils.d.ts'; // Allowed

这在一些特殊场景下是有帮助的,比如想直接导入声明文件中的类型定义。

但是通常不建议开启此选项,因为这会破坏模块的边界,将类型定义与模块实现混合在一起,不利于维护。

建议的方式是专门导出类型定义,或者直接导入模块的类型。

resolveJsonModule

它用于控制 TypeScript 编译器是否支持导入 JSON 文件作为模块。

TypeScript 2.9 版本起,通过设置 resolveJsonModule 选项为 true,TypeScript 编译器会自动解析并识别导入的 JSON 文件,无需手动添加类型声明文件。

使用这个选项的好处在于,当你需要导入配置文件、静态数据或其他 JSON 文件时,可以直接在 TypeScript 文件中导入并使用它们,而无需手动处理类型声明。TypeScript 编译器会在编译过程中将 JSON 文件转换为一个对象,可以直接按照对象的属性来访问 JSON 文件的内容。

emitDeclarationOnly

TypeScript 编译器只会生成类型声明文件(.d.ts 文件),而不会生成编译后的 JavaScript 文件。这对于创建类型声明库非常有,并且能够提高构建速度。

需要注意的是,如果设置了 emitDeclarationOnly,必须将 declaration 设置为 true

noEmit

当设置 noEmit 选项为 true 时,TypeScript 编译器将不会生成任何输出文件,包括 JavaScript 文件和类型声明文件(.d.ts 文件)。

这个选项通常在以下情况下使用:

  1. 代码检查:你只想进行 TypeScript 代码的类型检查,而不需要实际编译生成 JavaScript 文件。通过设置 noEmit 可以加快检查速度,特别是在大型项目中。
  2. 在编辑器中进行类型检查:一些编辑器和 IDE(如 Visual Studio Code)支持在保存 TypeScript 文件时进行实时类型检查。如果你只想在编辑器中进行类型检查而不需要生成文件,可以设置 noEmittrue

需要注意的是,如果设置了 noEmittrue,同时设置了其他与输出文件相关的选项(如 outDiroutFiledeclarationemitDeclarationOnly 等),那么 TypeScript 编译器会抛出一个错误,因为要生成输出文件。

jsx

它用于指定 TypeScript 文件中 JSX 语法的处理方式。

jsx 选项有以下几个可能的值:

  • "preserve": 这是默认值。当设置为 "preserve" 时,TypeScript 编译器会保留 JSX 语法不进行转换。这意味着 JSX 将会被传递给 React 或其他处理 JSX 的工具进行处理,而 TypeScript 不会对 JSX 语法进行解析和转换。
  • "react": 当设置为 "react" 时,TypeScript 编译器会将 JSX 语法转换为 React.createElement 函数调用。这是在不使用 JSX 转换工具(如 Babel)的情况下,直接使用 TypeScript 编译器进行 JSX 转换的方式。这样你就可以在 TypeScript 项目中直接使用 JSX 语法,而不需要额外的转换配置。
  • "react-jsx": 类似于 "react",当设置为 "react-jsx" 时,TypeScript 编译器会将 JSX 语法转换为 React.createElement 函数调用。这个选项在 TypeScript 2.1 版本引入,是为了与 React 16.0 版本之前的 JSX 语法兼容。
  • "react-jsxdev": 类似于 "react""react-jsx",当设置为 "react-jsxdev" 时,TypeScript 编译器会将 JSX 语法转换为 React.createElement 函数调用。这个选项在 TypeScript 2.1 版本引入,是为了与 React 16.0 版本之前的 JSX 语法兼容,同时支持使用开发工具。
  • "react-native": 当设置为 "react-native" 时,TypeScript 编译器会将 JSX 语法转换为 React.createElement 函数调用,类似于 "react",但与 React Native 一起使用。

importHelpers

它用于控制 TypeScript 是否在编译时自动引入辅助工具函数,以减少生成的 JavaScript 代码大小。

在使用 TypeScript 编译时,一些高级的 JavaScript 特性(如 async/await、generator、Promise 等)需要一些辅助函数来实现,这些辅助函数会被频繁地使用。默认情况下,TypeScript 会将这些辅助函数内联到每个文件中,这可能导致生成的 JavaScript 文件比较冗长,特别是当项目中有多个文件使用这些特性时。

importHelpers 选项的作用是将这些辅助函数抽取到单独的帮助模块中,然后在每个文件中通过 import 语句引入这个帮助模块。这样可以避免生成冗长的重复代码,减小最终生成的 JavaScript 文件的大小,提高代码的运行效率。

esModuleInterop

在 ES 模块系统中,导入和导出模块的语法是使用 importexport 关键字。而在 CommonJS 模块系统中,Node.js 早期使用的模块系统,导入模块的语法是使用 require,导出模块的语法是使用 module.exports

esModuleInterop 设置为 true 时,TypeScript 编译器会在生成的 JavaScript 代码中使用 ESM 格式来处理模块的导入和导出。同时,它还允许你在 TypeScript 代码中使用 import 来导入 CommonJS 格式的模块。

设置 esModuleInteroptrue 的好处是可以简化代码并提高互操作性。通过在 TypeScript 代码中使用 import 来导入 CommonJS 格式的模块,你可以统一使用一种导入导出的语法风格,避免混用 importrequire

allowSyntheticDefaultImports

用于允许从没有默认导出的模块中默认导入。

正常情况下,只有当一个模块明确导出一个默认值时,才可以使用默认导入语法导入该模块:

// module.ts
export default function foo() {}

// other.ts 
import func from './module';

但是有些模块没有默认导出值,这时默认导入语法将不被允许:

// module.ts
export function foo() {}

// other.ts
import func from './module'; // Error

allowSyntheticDefaultImports 选项允许使用默认导入语法,即使这个模块没有默认导出值:

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true  
  }
}

// other.ts
import func from './module'; // Allowed

这在一些特殊场景下是有用的,例如允许默认导入 CommonJS 模块。

// CommonJS module
module.exports = {
  foo() {
    // ...
  }  
}

// tsconfig.json
{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true 
  }
}

// TypeScript
import module from './module.js';

module.foo();

在这个例子中:

  1. module.js是一个 CommonJS 模块,使用module.exports导出对象而不是默认导出。
  2. 在tsconfig.json中开启allowSyntheticDefaultImports选项。
  3. 在TypeScript中可以直接默认导入这个模块,并像默认导出一样使用它。
  4. 这样使得导入 CommonJS 模块的语法与导入ES6模块的语法保持一致。
  5. TypeScript通过创建一个合成的默认导出来实现这一转换。

所以通过配置allowSyntheticDefaultImports,可以实现在TypeScript中将CommonJS模块平滑地默认导入的效果。

但是非必要场景下不建议开启此选项。因为这会破坏默认导入语法的语义,使得无法明确知道一个模块是否有默认导出,增加理解和维护的难度。

おすすめ

転載: juejin.im/post/7259715842873655333