typescript
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTypeScript Skill (2025-2026 Edition)
TypeScript 技能指南(2025-2026版)
This skill outlines the latest best practices for writing robust, performant, and type-safe TypeScript code, aligned with the 2025-2026 ecosystem (TypeScript 5.x and beyond).
本指南介绍了符合2025-2026生态(TypeScript 5.x及更高版本)的编写健壮、高性能、类型安全的TypeScript代码的最新最佳实践。
🚀 Key Trends & Features (2025/2026)
🚀 核心趋势与特性(2025/2026)
- Native Speed: The transition to a Go-based compiler (native port) is underway (TS 7+), promising massive performance gains.
- Default Strictness: Modern projects treat as the absolute baseline.
strict: true - Framework First: TS is now deeply integrated into frameworks (Next.js, Remix, NestJS) rather than an add-on.
- 原生性能: 基于Go实现的编译器(原生移植)正在推进中(TS 7+),有望带来大幅性能提升。
- 默认严格模式: 现代项目将作为绝对基础配置。
strict: true - 框架优先: TS现在已深度集成到各个框架(Next.js、Remix、NestJS)中,而非附加组件。
🛠️ Configuration Best Practices (tsconfig.json
)
tsconfig.json🛠️ 配置最佳实践(tsconfig.json
)
tsconfig.jsonUse strict defaults to prevent bugs before they happen.
json
{
"compilerOptions": {
/* Type Safety */
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"useUnknownInCatchVariables": true,
"noUncheckedIndexedAccess": true, /* 2025 Essential: Prevents accessing undefined array indices */
"exactOptionalPropertyTypes": true, /* Stricter optional property checks */
/* Modules & Emit */
"module": "NodeNext", /* or "ESNext" for pure frontend */
"moduleResolution": "NodeNext", /* Aligns with modern Node.js ESM */
"target": "ES2022", /* Modern runtimes support recent ES features */
"skipLibCheck": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"verbatimModuleSyntax": true, /* Enforces strict import/export syntax (TS 5.0+) */
/* Developer Experience */
"allowSyntheticDefaultImports": true
}
}使用严格默认配置,提前规避Bug。
json
{
"compilerOptions": {
/* Type Safety */
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"useUnknownInCatchVariables": true,
"noUncheckedIndexedAccess": true, /* 2025必备:防止访问未定义的数组索引 */
"exactOptionalPropertyTypes": true, /* 更严格的可选属性检查 */
/* Modules & Emit */
"module": "NodeNext", /* 纯前端项目可使用"ESNext" */
"moduleResolution": "NodeNext", /* 适配现代Node.js ESM规范 */
"target": "ES2022", /* 现代运行时支持最新ES特性 */
"skipLibCheck": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"verbatimModuleSyntax": true, /* 强制执行严格的导入/导出语法(TS 5.0+支持) */
/* Developer Experience */
"allowSyntheticDefaultImports": true
}
}🧩 Type Safety & Patterns
🧩 类型安全与常用模式
1. unknown
over any
unknownany1. 优先使用unknown
而非any
unknownanyNever use unless absolutely necessary (e.g., migrating legacy code). Use and narrow the type safely.
anyunknowntypescript
// ❌ Bad
function processData(input: any) {
input.doSomething(); // Runtime crash risk
}
// ✅ Good
function processData(input: unknown) {
if (typeof input === 'string') {
console.log(input.toUpperCase()); // Safe
} else if (isCustomType(input)) {
input.doSomething(); // Safe via type guard
}
}除非万不得已(比如迁移遗留代码),绝对不要使用。请使用并安全收窄类型。
anyunknowntypescript
// ❌ 错误示例
function processData(input: any) {
input.doSomething(); // 存在运行时崩溃风险
}
// ✅ 正确示例
function processData(input: unknown) {
if (typeof input === 'string') {
console.log(input.toUpperCase()); // 类型安全
} else if (isCustomType(input)) {
input.doSomething(); // 通过类型守卫保证安全
}
}2. satisfies
Operator (TS 4.9+)
satisfies2. satisfies
运算符(TS 4.9+)
satisfiesUse to validate a value matches a type without widening the type (preserving inference).
satisfiestypescript
type Config = Record<string, string | number>;
const myConfig = {
port: 8080,
host: "localhost"
} satisfies Config;
// ✅ TS knows 'port' is a number directly, no casting needed.
myConfig.port.toFixed(2); 使用验证值是否匹配类型,同时不会拓宽类型(保留原有类型推断)。
satisfiestypescript
type Config = Record<string, string | number>;
const myConfig = {
port: 8080,
host: "localhost"
} satisfies Config;
// ✅ TS可以直接识别'port'是数字类型,无需强制转换
myConfig.port.toFixed(2); 3. Immutable Data by Default
3. 默认使用不可变数据
Use to prevent accidental mutations, especially for function arguments and React props.
readonlytypescript
interface User {
readonly id: string;
readonly name: string;
tags: readonly string[]; // Immutable array
}
function printTags(tags: readonly string[]) {
// tags.push("new"); // ❌ Error: Property 'push' does not exist on type 'readonly string[]'
}使用防止意外修改,尤其是函数参数和React props。
readonlytypescript
interface User {
readonly id: string;
readonly name: string;
tags: readonly string[]; // 不可变数组
}
function printTags(tags: readonly string[]) {
// tags.push("new"); // ❌ 报错:类型'readonly string[]'上不存在属性'push'
}4. Template Literal Types
4. 模板字面量类型
Create precise string types for better autocompletion and safety.
typescript
type EventName = "click" | "hover";
type HandlerName = `on${Capitalize<EventName>}`; // "onClick" | "onHover"创建精确的字符串类型,实现更好的自动补全和类型安全。
typescript
type EventName = "click" | "hover";
type HandlerName = `on${Capitalize<EventName>}`; // 结果为"onClick" | "onHover"⚡ Performance Optimization
⚡ 性能优化
- Type Imports: Use or
import type { ... }explicitly. Enablingimport { type ... }enforces this, ensuring zero JS overhead for type-only imports using modern bundlers.verbatimModuleSyntax - Lazy Loading: Leverage for splitting code in large applications.
await import(...)
- 类型导入: 显式使用或者
import type { ... }。开启import { type ... }可强制执行该规则,确保现代打包器处理仅类型导入时不会产生任何JS运行时开销。verbatimModuleSyntax - 懒加载: 在大型应用中使用拆分代码。
await import(...)
⚠️ Common Pitfalls to Avoid
⚠️ 需要避免的常见陷阱
- Excessive Type Assertions (): Use type guards or
asfor validation instead of forcing types withzod.as - Broad Types: Avoid or
Function. Useobjector() => voidinstead.Record<string, unknown> - Enum Misuse: Prefer union types of strings () over standard TS
type Status = 'open' | 'closed's to keep runtime code cleaner and avoid nominal typing surprises.enum
- 滥用类型断言(): 请使用类型守卫或者
as做验证,而非用zod强制指定类型。as - 过宽的类型: 避免使用或者
Function,请改用object或者() => void。Record<string, unknown> - 误用Enum: 优先使用字符串联合类型()而非标准TS
type Status = 'open' | 'closed',可以让运行时代码更简洁,避免名义类型的意外问题。enum