本篇主讲TypeScript 的 tsconfig.json 中常见的面试题
TypeScript 的 tsconfig.json 中有哪些配置项信息?
-
files:一个包含指定文件的相对或绝对路径的数组列表,用于指定待编译文件。编译器只会编译在files中列出的文件,其他文件将被忽略。例如:
jsonCopy code "files": [ "src/main.ts", "src/utils.ts"] -
include和exclude:用于指定要编译的文件或排除的文件的规则。include是一个包含文件或文件夹的数组,用于匹配要编译的文件。它使用 glob 模式进行匹配。exclude是一个包含文件或文件夹的数组,用于排除不想编译的文件。也使用 glob 模式进行匹配。例如:
jsonCopy code "include": [ "src/**/*.ts"], "exclude": [ "src/**/*.test.ts", "node_modules"] -
compileOnSave:设置为true后,IDE 在保存文件时会根据tsconfig.json重新生成文件。 -
extends:可以通过指定另一个tsconfig.json文件的路径,来继承该配置文件中的配置。这对于共享一些通用配置非常有用。例如:
jsonCopy code "extends": "./configs/base-tsconfig.json" -
compilerOptions:这是最重要的部分,用于配置 TypeScript 编译器的选项。在
compilerOptions中,您可以设置一系列选项,如输出目标 (target)、模块化系统 (module)、是否启用严格模式 (strict)、输出目录 (outDir) 等。例如:
jsonCopy code "compilerOptions": { "target": "ES6", "module": "CommonJS", "strict": true, "outDir": "./dist" }这些是
tsconfig.json中最常用的配置项,它们使您能够对 TypeScript 项目进行高度定制化的配置,以满足您的编译需求。
我没搞懂files和include的区别
没问题,让我来解释一下 files 和 include 在 tsconfig.json 中的区别。
-
files:使用
files配置,您需要逐个列出每个要编译的文件的路径,不支持使用通配符来匹配多个文件。例如:
jsonCopy code "files": [ "src/main.ts", "src/utils.ts"]在这个例子中,只有
src/main.ts和src/utils.ts这两个文件会被编译,其他任何 TypeScript 文件都会被排除。 -
include:它使用 Glob 模式来匹配文件路径。
使用
include配置,您可以使用通配符来匹配多个文件或目录,从而更灵活地选择要编译的文件。例如:
jsonCopy code "include": [ "src/**/*.ts", "test/**/*.ts"]在这个例子中,所有位于
src和test目录以及它们的子目录下的.ts文件都会被包含在编译过程中。关键区别:
files是显式列出要编译的文件的路径,不支持通配符匹配,只编译指定的文件。include是使用 Glob 模式匹配要编译的文件或目录,支持通配符匹配,可以灵活选择要编译的文件。
通常情况下,建议使用 include 配置来选择要编译的文件,因为它提供了更大的灵活性和便利性。使用 files 配置通常是在一些特殊情况下,您确切知道要编译的文件并且不需要灵活性时使用。
相同点:
- 都是数组类型,可以包含多个文件路径或匹配模式。
- 都用于告诉 TypeScript 编译器哪些文件需要参与编译。
什么是glob模式
Glob 模式是一种用于匹配文件路径的简单模式匹配规则。它通常用于命令行和构建工具中,用于选择文件或目录,或者进行文件路径的模式匹配。
在 Glob 模式中,可以使用通配符来匹配文件路径的不同部分。以下是一些常用的通配符:
- `` :匹配任意字符,除了路径分隔符
/。 *:匹配任意数量的目录,用于递归匹配子目录。?:匹配单个字符。[]:匹配括号中的任意字符。{}:匹配大括号中逗号分隔的多个模式中的一个。!:在模式的开头用于否定匹配。
例如,假设我们有以下文件结构:
- src
- utils
- helper.ts
- utility.ts
- main.ts
- test
- test-utils.ts
以下是一些 Glob 模式的示例及其匹配结果:
src/*.ts:匹配src目录下所有的.ts文件,结果为src/main.ts。src/**/*.ts:匹配src目录及其所有子目录下的.ts文件,结果为src/main.ts、src/utils/helper.ts和src/utils/utility.ts。*/*.ts:匹配项目中所有子目录中的.ts文件,结果为src/main.ts、src/utils/helper.ts、src/utils/utility.ts和test/test-utils.ts。*/test-*.ts:匹配所有文件名以test-开头且扩展名为.ts的文件,结果为test/test-utils.ts。
Glob 模式提供了一种简单而强大的方法来选择和匹配文件路径,特别是在构建和管理项目时非常有用。在 tsconfig.json 中,include 和 exclude 配置项使用的就是 Glob 模式,以指定要编译的文件和排除的文件。
compileOnSave:true 让IDE在保存文件的时候根据tsconfig.json重新生成文件。
这里重新生成,生成的是什么文件
设置 compileOnSave: true 后,IDE 在保存 TypeScript 文件时,会根据 tsconfig.json 中的配置重新生成文件。这里所说的重新生成文件指的是将 TypeScript 文件编译为 JavaScript 文件,并根据 compilerOptions 中的配置项生成对应的 JavaScript 代码。
具体来说,生成的文件包括:
- JavaScript 文件:对应的 TypeScript 文件会被编译为 JavaScript 文件,并输出到指定的输出目录(通过
outDir配置项指定)。 - Map 文件:TypeScript 编译器会生成对应的
.map文件,用于在调试时将编译后的 JavaScript 代码映射回原始 TypeScript 代码。这对于在浏览器中调试时很有用,因为它允许开发者在浏览器的开发者工具中看到 TypeScript 源码的调试信息。 - 声明文件(.d.ts 文件) :如果 TypeScript 文件中使用了声明文件(
.d.ts)或配置了declaration: true,编译器会生成对应的声明文件,用于描述 TypeScript 文件中定义的类型、接口、类等信息。这对于将 TypeScript 代码作为库包供他人使用时,提供类型信息是非常有用的。
因此,compileOnSave: true 选项会在保存 TypeScript 文件时触发 TypeScript 编译器重新生成 JavaScript 文件以及相关的辅助文件,确保项目中的代码始终保持最新的状态。这对于实时检测代码错误和调试非常有用,并且确保生成的 JavaScript 代码符合项目的配置要求。
和noemit区别是什么
noEmit 和 compileOnSave 是 TypeScript 配置中两个不同的选项,它们的作用和影响有一些区别。
-
noEmit:
noEmit是 TypeScript 编译选项中的一个配置项,它用于控制 TypeScript 编译器是否生成任何输出文件(即是否生成编译后的 JavaScript 文件)。- 当
noEmit设置为true时,TypeScript 编译器将不会生成任何输出文件,即使在编译过程中没有出现错误也不会产生编译后的 JavaScript 文件。 - 这对于只进行类型检查而不需要实际生成 JavaScript 文件的情况很有用,比如在开发阶段只关注类型检查,而不需要实际运行代码的情况。
-
compileOnSave:
compileOnSave是一种 IDE(集成开发环境)特有的配置选项,它并不是 TypeScript 编译器的选项,而是用于在 IDE 中控制在保存文件时触发 TypeScript 编译器重新编译。- 当
compileOnSave设置为true时,IDE 在保存 TypeScript 文件时会触发 TypeScript 编译器重新编译该文件,根据项目中的tsconfig.json中的配置重新生成 JavaScript 文件以及相关的辅助文件(如声明文件和 Map 文件)。 - 这样可以在保存文件后立即看到最新的编译结果,并在 IDE 中实时检测代码错误。
因此,noEmit 主要用于控制 TypeScript 编译器是否生成编译后的 JavaScript 文件,而 compileOnSave 则是用于 IDE 中实现在保存文件时触发编译的功能,以便及时反馈编译结果和代码错误。这两个选项分别对应了不同的编译阶段,分别是是否生成输出文件和何时触发编译过程。
详解一下compilerOptions
"compilerOptions": {
"target": "ES6",
/*
指定编译的目标 ECMAScript 版本。
可选值有 "ES3"、"ES5"、"ES6"、"ES2015" 等。
选择不同的目标版本会影响编译后代码的兼容性和特性支持。
*/
"module": "CommonJS",
/*
指定生成的模块化代码的模块系统。
可选值有 "CommonJS"、"AMD"、"ES6"、"System" 等。
选择不同的模块系统可以适应不同的项目环境。
*/
"outDir": "./dist",
/*
指定输出目录,即编译后的 JavaScript 文件输出的位置。
该路径是相对于 tsconfig.json 文件的位置。
*/
"strict": true,
/*
启用严格的类型检查选项。
设置为 true 表示启用所有严格检查,包括 noImplicitAny、strictNullChecks、strictFunctionTypes 等。
*/
"esModuleInterop": true,
/*
启用该选项后,TypeScript 将使用更简洁的导入语法以兼容 CommonJS 和 ES6 模块系统之间的交互。
例如,import * as module from 'module' 将被转换为 const module = require('module')。
*/
"allowJs": true,
/*
允许编译器编译 JavaScript 文件。
这在迁移现有 JavaScript 代码到 TypeScript 时很有用,以便 TypeScript 可以对 JavaScript 文件进行类型检查。
*/
"checkJs": true,
/*
启用对 JavaScript 文件的类型检查。
该选项与 allowJs 配合使用,用于在 JavaScript 文件中进行类型检查,以捕获潜在的类型错误。
*/
"noEmit": true
/*
设置为 true 后,TypeScript 编译器不会生成任何输出文件。
这对于只进行类型检查而不需要生成 JavaScript 文件的情况很有用。
*/
}
问:allowjs,什么意思,还可以对js做类型检查?js里面没有声明类型怎么办
对的,allowJs: true 允许 TypeScript 编译器编译 JavaScript 文件,并且即使 JavaScript 文件没有显式声明类型,TypeScript 仍然会尝试进行类型检查。
在 TypeScript 中,如果启用了 allowJs 选项,TypeScript 编译器会将 JavaScript 文件视为动态类型(Dynamic Typing)的代码,并尝试根据代码的上下文推断变量和函数的类型。虽然 JavaScript 自身是一门动态类型语言,没有显式的类型声明,但 TypeScript 能够根据变量的使用情况和运算符的操作等信息推断出潜在的类型。
例如,在以下 JavaScript 代码中:
javascriptCopy code
function add(a, b) {
return a + b;
}
const result = add(5, 10);
console.log(result);
当 allowJs: true 时,TypeScript 会尝试根据函数 add 的使用推断出参数 a 和 b 可能是数字类型,并返回一个数字类型。然后,它会根据 result 变量的使用推断出它是一个数字类型,并且在类型检查时,如果出现 add 函数参数类型错误或 result 变量类型错误的情况,TypeScript 会给出相应的类型错误提示。
虽然 TypeScript 可以对 JavaScript 文件进行类型推断和类型检查,但是由于 JavaScript 本身没有显式的类型声明,所以推断的准确性可能受限。因此,如果想要更精确地进行类型检查,建议在 JavaScript 代码中添加 TypeScript 的类型声明,或者将代码逐步转换为 TypeScript 文件。这样可以确保类型检查的准确性,并获得更多 TypeScript 的类型优势。
TypeScript 中如何设置模块导入的路径别名?
通过 tsconfig.json 中的 paths 项来配置:
json复制代码 { "compilerOptions": { "baseUrl": ".", "paths": { "@helper/*": ["src/helper/*"], "@utils/*": ["src/utils/*"], ... } } }
解析
baseUrl: "." 表示 TypeScript 编译器在解析模块导入时的基本路径(Base Path)。换句话说,当编译器遇到类似于 import 或 require 的语句时,会将这个基本路径作为起点来解析导入的模块路径。
在上面的配置中,baseUrl 被设置为 "." ,意味着 TypeScript 编译器会将当前项目的根目录作为起始路径来解析模块导入。这样配置后,当我们在项目中使用绝对路径导入模块时,可以更简洁地引用模块,不需要写出完整的相对路径。
例如,假设有以下文件结构:
cssCopy code
- src
|- helper
| |- helper1.ts
| |- helper2.ts
|- utils
| |- utils1.ts
| |- utils2.ts
|- main.ts
- tsconfig.json
有了上述配置后,我们可以在 main.ts 文件中这样导入模块:
typescriptCopy code
import { something } from "@helper/helper1";
import { doSomething } from "@utils/utils1";
编译器会根据 baseUrl 和 paths 配置将这些模块导入正确地解析为实际的路径,即:
@helper/*会被解析为src/helper/*,所以@helper/helper1导入实际指向src/helper/helper1.ts。@utils/*会被解析为src/utils/*,所以@utils/utils1导入实际指向src/utils/utils1.ts。
这样配置可以帮助我们简化模块导入的路径,使代码更具可读性和可维护性。
关于 paths 属性,它是一个映射对象,用于将自定义的模块路径别名映射到实际的文件路径。在上面的例子中,我们定义了 @helper/* 和 @utils/* 别名,并将它们映射到 src/helper/* 和 src/utils/* 的路径。由于 paths 属性允许定义多个映射,所以它接收一个数组来表示多个映射。每个映射定义中,键表示别名,值表示实际的文件路径。