【TypeScript】关于设置文件tsconfig.json
@TOC
推荐超级课程:
target
- 指定输出JavaScript的版本
- 默认为
ES5
- 适当设置可以
- 缩短编译时间
- 提高运行时的执行效率
- 强化开发时的类型检查
target选项各自的差异
比较不同target选项的输出代码
- TypeScript代码(原始代码)
const fetchData = async (url: string): Promise<{ data: string }> => {
const response = await fetch(url);
return { data: await response.text() };
};
- JavaScript代码(输出代码)
target: "ES5"
的情况下
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 fetchData = function (url) {
return __awaiter(this, void 0, void 0, function () {
var response, text;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
return [4 /*yield*/, fetch(url)];
case 1:
response = _a.sent();
return [4 /*yield*/, response.text()];
case 2:
text = _a.sent();
return [2 /*return*/, { data: text }];
}
});
});
};
target: "ES2015"
的情况下
const fetchData = async (url) => {
const response = await fetch(url);
return { data: await response.text() };
};
target: "ES5"
→ async/await被转换为基于Promise的代码target: "ES2015"
→ async/await可以直接使用
→ 编译到ES2015时,
- 代码量减少,输出文件大小变小 → 编译时间缩短
- 可以利用最新语法,JIT编译器的优化更容易生效 → 运行时执行效率提高
target选项各自的lib差异
改变target时,类型检查使用的lib的默认值也会改变。target: "ES5"
的情况下,lib的默认值为lib: ["es5", "dom", "dom.iterable"]
→ Promise不在lib中,因此以下代码会出现类型错误
const promise: Promise<string> = new Promise(resolve => resolve("Hello")); // 错误: 找不到名称'Promise'。
target为"ES2015"
的情况下,lib的默认值为lib: ["es2015", "dom", "dom.iterable"]
→ Promise包含在es2015中,因此不会出现类型错误
选择最合适的target
根据输出JavaScript代码的运行环境选择
- 在浏览器上运行的情况下
- 与支持的最旧浏览器版本相匹配
- 例如: Chrome最新版 / Safari最新版 / Firefox最新版 →
target: "ES2022"
(参考兼容表 )
- 在Node.js上运行的情况下
- 与生产环境的Node.js版本相匹配
- 例如: Node.js 22 → target: “ES2022”(从tsconfig/bases 参考@tsconfig/node22 )
lib
- 指定类型检查时引用的标准库
- 根据target设置lib的默认值,但显式设置lib可以选择适合环境的类型定义
lib选项各自的差异
"target": "ES2022",
"lib": ["ES2022"] // "target": "ES2022"时的默认值
的情况下,ES2022中不包含fetch,因此以下代码会出现类型错误
fetch("https://example.com"); // 找不到名称'fetch'。
使用浏览器API(如fetch或document等)时,需要向lib添加DOM
"target": "ES2022",
"lib": ["ES2022", "DOM"]
选择最合适的lib
根据输出JavaScript代码的运行环境进行选择
在浏览器上运行的情况下
- 为了能够使用fetch和document的类型,需要设置"DOM"或"DOM.Iterable"。
- 例如:
"target": "ES2022", "lib": ["ES2022", "dom", "dom.iterable"]
在Node.js上运行的情况下
- 即使
target
为"ES2022",也应尽量选择"ES2024"等以适应最新的JavaScript规范。- “ESNext"可以始终反映最新的JavaScript规范,但由于TypeScript的更新可能会带来意外的变化,因此最好避免使用。
- “ES2024"被指定时,后续的API在类型检查上可以被使用,因此为了防止运行时错误,需要确认并必要时引入polyfill。
- 例如:
"target": "ES2022", "lib": ["ES2024"]
- 即使
module
- 指定输出JavaScript代码的模块系统
- 默认值
target: "ES5"
的情况下 → CommonJS- 其他情况 → ES6
- 如果不适当设置,可能会在环境之间引起import/require的兼容性错误
- ESModules环境下使用require →
SyntaxError: Cannot use require in ES module scope
- CommonJS环境下使用import →
SyntaxError: Cannot use import statement outside a module
- ESModules环境下使用require →
module选项各自的差异
- TypeScript代码(原始代码)
// module.ts
export function greet(name: string) {
return `Hello, ${name}!`;
}
// index.ts
import { greet } from "./module";
console.log(greet("Alice"));
- JavaScript代码(输出代码)
"module": "CommonJS"
的情况下
// module.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.greet = void 0;
function greet(name) {
return `Hello, ${name}!`;
}
exports.greet = greet;
// index.js
"use strict";
const { greet } = require("./module");
console.log(greet("Alice"));
"module": "esnext"/"nodenext"
的情况下
// module.js
export function greet(name) {
return `Hello, ${name}!`;
}
// index.js
import { greet } from "./module.js";
console.log(greet("Alice"));
选择最合适的module
- 选择
"esnext"/"nodenext"
(JavaScript代码以ESM方式输出)- 使用ESM可以更有效地重用和管理代码
- 在浏览器上运行的情况下 →
esnext
- 使用最新的ECMAScript特性,可以直接在现代浏览器中使用import/export
- 在Node.js上运行的情况下 →
nodenext
- Node.js可以同时使用ESM和CommonJS两种模块形式,因此可以根据需要处理这两种格式
moduleResolution
- 指定在编译时如何按照特定文件类型进行查找的顺序
- 默认值
module: "node16"/"nodenext"
的情况下 →"node16"/"nodenext"
- 其他情况 →
node
- 如果不适当设置,可能会导致文件或类型无法正确找到,从而在构建或运行时发生错误
Cannot find module 'xxx'
Cannot find module 'xxx' or its corresponding type declarations.
TypeError: xxx is not a function
moduleResolution选项各自的差异
TypeScript代码(原始代码)
/project
├── src/
│ ├── index.ts
│ ├── utils.ts
├── node_modules/
│ ├── some-package/
│ │ ├── package.json
│ │ ├── index.js
│ │ ├── index.mjs
│ │ ├── index.cjs
src/utils.ts
export const helper = () => console.log("Helper function");
node_modules/some-package/package.json
{
"main": "./index.js",
"exports": {
"import": "./index.mjs",
"require": "./index.cjs"
}
}
选择最合适的moduleResolution
根据输出的JavaScript代码的运行环境进行选择
- 在浏览器上运行的情况下(使用Vite、Webpack等打包工具) →
bundler
→ 打包工具会处理ESM和CommonJS的差异 - 在Node.js上运行的情况下 →
node16
或nodenext
→ 可以同时处理ESM和CommonJS
总结
输出的JavaScript代码如果是
- 在浏览器上运行的情况下
{
"target": "ES2023", // 主要针对最新的主流浏览器(如Chrome、Edge、Firefox、Safari等)
"lib": ["ES2023", "DOM", "DOM.Iterable"], // 可以引用浏览器API的类型
"module": "esnext", // 使用最新的模块系统
"moduleResolution": "bundler" // 采用针对打包工具优化的模块解析方式
}
- 在Node.js上运行的情况下
{
"target": "ES2023", // 针对Node.js 22版本
"lib": ["ES2024"], // 可以引用ES2024标准库的类型
"module": "nodenext", // 使用Node.js支持ESM和CJS的模块系统
"moduleResolution": "nodenext" // 采用Node.js的模块解析方式
}