TypeScript 编译器与配置详解
更新: 8/21/2025 字数: 0 字 时长: 0 分钟
深入理解 TypeScript 编译器的工作原理、配置选项以及最新发展动态。
tsconfig.json 精解
基础配置结构
json
{
"compilerOptions": {
// 编译选项
},
"include": [
// 包含的文件模式
],
"exclude": [
// 排除的文件模式
],
"extends": "./base-config.json", // 继承配置
"files": [
// 明确指定的文件列表
],
"references": [
// 项目引用
]
}
核心编译选项详解
基础选项
json
{
"compilerOptions": {
// 目标 JavaScript 版本
"target": "ES2020", // ES3, ES5, ES2015, ES2016, ES2017, ES2018, ES2019, ES2020, ES2021, ES2022, ESNext
// 模块系统
"module": "ESNext", // CommonJS, AMD, System, UMD, ES6, ES2015, ES2020, ESNext, Node16, NodeNext
// 模块解析策略
"moduleResolution": "node", // node, classic, bundler
// 包含的库文件
"lib": ["ES2020", "DOM", "DOM.Iterable"],
// 输出目录
"outDir": "./dist",
// 根目录
"rootDir": "./src",
// 基础路径
"baseUrl": ".",
// 路径映射
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@utils/*": ["src/utils/*"]
}
}
}
严格类型检查
json
{
"compilerOptions": {
// 启用所有严格类型检查选项
"strict": true,
// 等价于以下选项的组合:
"noImplicitAny": true, // 禁止隐式 any
"strictNullChecks": true, // 严格空值检查
"strictFunctionTypes": true, // 严格函数类型检查
"strictBindCallApply": true, // 严格 bind/call/apply 检查
"strictPropertyInitialization": true, // 严格属性初始化检查
"noImplicitThis": true, // 禁止隐式 this
"alwaysStrict": true, // 始终以严格模式解析
"exactOptionalPropertyTypes": true, // 精确可选属性类型
"noImplicitReturns": true, // 禁止隐式返回
"noFallthroughCasesInSwitch": true, // 禁止 switch 语句贯穿
"noUncheckedIndexedAccess": true, // 禁止未检查的索引访问
"noImplicitOverride": true, // 禁止隐式重写
"noPropertyAccessFromIndexSignature": true // 禁止从索引签名访问属性
}
}
模块和解析选项
json
{
"compilerOptions": {
// ES 模块互操作
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
// 模块检测
"moduleDetection": "auto", // auto, legacy, force
// 解析 JSON 模块
"resolveJsonModule": true,
// 允许导入 .ts 扩展名
"allowImportingTsExtensions": true,
// 类型根目录
"typeRoots": ["./node_modules/@types", "./types"],
// 包含的类型包
"types": ["node", "jest", "express"],
// 强制一致的文件名大小写
"forceConsistentCasingInFileNames": true
}
}
输出控制
json
{
"compilerOptions": {
// 生成声明文件
"declaration": true,
"declarationDir": "./types",
"declarationMap": true,
// 生成源映射
"sourceMap": true,
"inlineSourceMap": false,
"inlineSources": false,
// 移除注释
"removeComments": true,
// 不生成输出文件
"noEmit": false,
"noEmitOnError": true,
// 仅生成声明文件
"emitDeclarationOnly": false,
// 保留 const 枚举
"preserveConstEnums": true,
// 导入助手函数
"importHelpers": true,
// 降级迭代器
"downlevelIteration": true
}
}
实验性功能
json
{
"compilerOptions": {
// 装饰器支持
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
// 使用 define 语义处理类字段
"useDefineForClassFields": true,
// JSX 支持
"jsx": "react-jsx", // preserve, react, react-jsx, react-jsxdev, react-native
"jsxFactory": "React.createElement",
"jsxFragmentFactory": "React.Fragment",
"jsxImportSource": "react"
}
}
项目引用配置
json
// 主项目 tsconfig.json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true
},
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/utils" },
{ "path": "./packages/ui" }
]
}
// 子项目 packages/core/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"references": [
{ "path": "../utils" }
]
}
配置继承示例
json
// tsconfig.base.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
// tsconfig.json (开发环境)
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"sourceMap": true,
"noEmit": true
},
"include": ["src/**/*", "tests/**/*"]
}
// tsconfig.build.json (生产构建)
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"declaration": true,
"removeComments": true
},
"include": ["src/**/*"],
"exclude": ["**/*.test.ts", "**/*.spec.ts"]
}
TypeScript 编译器 (tsc) 核心流程解析
编译流程概览
1. 词法分析阶段 (Lexical Analysis)
typescript
// 源代码
const message: string = "Hello, TypeScript!";
// 词法分析后的 Token 流
[
{ kind: SyntaxKind.ConstKeyword, text: "const" },
{ kind: SyntaxKind.Identifier, text: "message" },
{ kind: SyntaxKind.ColonToken, text: ": " },
{ kind: SyntaxKind.StringKeyword, text: "string" },
{ kind: SyntaxKind.EqualsToken, text: " = " },
{ kind: SyntaxKind.StringLiteral, text: '"Hello, TypeScript!"' },
{ kind: SyntaxKind.SemicolonToken, text: ";" }
]
2. 语法分析阶段 (Parsing)
typescript
// AST 节点结构示例
interface VariableStatement {
kind: SyntaxKind.VariableStatement;
declarationList: {
kind: SyntaxKind.VariableDeclarationList;
flags: NodeFlags.Const;
declarations: [{
kind: SyntaxKind.VariableDeclaration;
name: { kind: SyntaxKind.Identifier; text: "message" };
type: { kind: SyntaxKind.StringKeyword };
initializer: {
kind: SyntaxKind.StringLiteral;
text: "Hello, TypeScript!"
};
}];
};
}
3. 类型检查阶段 (Type Checking)
typescript
// 类型检查器的核心职责
class TypeChecker {
// 符号表管理
private symbolTable: Map<string, Symbol> = new Map();
// 类型推断
inferType(node: Expression): Type {
switch (node.kind) {
case SyntaxKind.StringLiteral:
return this.stringType;
case SyntaxKind.NumericLiteral:
return this.numberType;
case SyntaxKind.Identifier:
return this.getTypeOfSymbol(this.getSymbol(node));
// ... 更多类型推断逻辑
}
}
// 类型兼容性检查
isTypeAssignableTo(source: Type, target: Type): boolean {
// 结构化类型系统的兼容性检查
if (source === target) return true;
if (target.flags & TypeFlags.Any) return true;
if (source.flags & TypeFlags.Never) return true;
// 对象类型兼容性
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
return this.isObjectTypeAssignableTo(source, target);
}
return false;
}
// 泛型实例化
instantiateType(type: Type, typeArguments: Type[]): Type {
if (type.flags & TypeFlags.TypeParameter) {
const index = (type as TypeParameter).index;
return typeArguments[index] || type;
}
// ... 更多实例化逻辑
return type;
}
}
4. 代码生成阶段 (Emit)
typescript
// 代码生成器示例
class Emitter {
private output: string = "";
emitVariableStatement(node: VariableStatement): void {
const declaration = node.declarationList.declarations[0];
const isConst = node.declarationList.flags & NodeFlags.Const;
// 根据目标版本选择关键字
const keyword = this.target >= ScriptTarget.ES2015 && isConst ? "const" : "var";
this.output += `${keyword} ${declaration.name.text}`;
if (declaration.initializer) {
this.output += " = ";
this.emitExpression(declaration.initializer);
}
this.output += ";\n";
}
emitTypeAssertion(node: TypeAssertion): void {
// TypeScript: value as Type
// JavaScript: value (类型断言被移除)
this.emitExpression(node.expression);
}
}
编译器 API 使用示例
typescript
import * as ts from "typescript";
// 创建编译器程序
function createProgram(fileNames: string[], options: ts.CompilerOptions): ts.Program {
return ts.createProgram(fileNames, options);
}
// 类型检查
function typeCheck(program: ts.Program): void {
const checker = program.getTypeChecker();
for (const sourceFile of program.getSourceFiles()) {
if (!sourceFile.isDeclarationFile) {
ts.forEachChild(sourceFile, visit);
}
}
function visit(node: ts.Node) {
if (ts.isVariableDeclaration(node) && node.initializer) {
const type = checker.getTypeAtLocation(node.initializer);
const typeString = checker.typeToString(type);
console.log(`Variable ${node.name.getText()} has type: ${typeString}`);
}
ts.forEachChild(node, visit);
}
}
// 自定义转换器
function createTransformer(): ts.TransformerFactory<ts.SourceFile> {
return (context: ts.TransformationContext) => {
return (sourceFile: ts.SourceFile) => {
function visitor(node: ts.Node): ts.Node {
// 移除所有 console.log 调用
if (ts.isCallExpression(node) &&
ts.isPropertyAccessExpression(node.expression) &&
node.expression.expression.getText() === "console" &&
node.expression.name.text === "log") {
return ts.factory.createVoidZero();
}
return ts.visitEachChild(node, visitor, context);
}
return ts.visitNode(sourceFile, visitor);
};
};
}
为什么最近 TypeScript 用 Go 重构
背景与动机
1. 性能瓶颈
typescript
// 当前 TypeScript 编译器的性能问题
// 大型项目编译时间
interface CompilationStats {
projectSize: string;
currentCompileTime: string;
targetCompileTime: string;
improvement: string;
}
const performanceComparison: CompilationStats[] = [
{
projectSize: "小型项目 (<100 文件)",
currentCompileTime: "2-5 秒",
targetCompileTime: "<1 秒",
improvement: "50-80%"
},
{
projectSize: "中型项目 (100-1000 文件)",
currentCompileTime: "10-30 秒",
targetCompileTime: "3-8 秒",
improvement: "60-75%"
},
{
projectSize: "大型项目 (>1000 文件)",
currentCompileTime: "1-5 分钟",
targetCompileTime: "10-30 秒",
improvement: "70-90%"
}
];
2. 内存使用优化
go
// Go 版本的内存管理优势
package main
import (
"fmt"
"runtime"
"sync"
)
// 并发类型检查
type TypeChecker struct {
symbolTable sync.Map
typeCache sync.Map
workers int
}
func (tc *TypeChecker) CheckFilesParallel(files []string) {
semaphore := make(chan struct{}, tc.workers)
var wg sync.WaitGroup
for _, file := range files {
wg.Add(1)
go func(filename string) {
defer wg.Done()
semaphore <- struct{}{} // 获取信号量
defer func() { <-semaphore }() // 释放信号量
tc.checkFile(filename)
}(file)
}
wg.Wait()
}
// 内存池复用
var astNodePool = sync.Pool{
New: func() interface{} {
return &ASTNode{}
},
}
func (tc *TypeChecker) parseFile(filename string) *ASTNode {
node := astNodePool.Get().(*ASTNode)
defer astNodePool.Put(node)
// 解析逻辑
return node
}
3. 并发处理能力
go
// Go 的并发优势:Goroutines
package compiler
import (
"context"
"sync"
)
type CompilerPipeline struct {
lexerChan chan LexerJob
parserChan chan ParserJob
checkerChan chan CheckerJob
emitterChan chan EmitterJob
}
func (cp *CompilerPipeline) ProcessFiles(ctx context.Context, files []string) {
var wg sync.WaitGroup
// 启动各阶段的 worker goroutines
for i := 0; i < runtime.NumCPU(); i++ {
wg.Add(4)
// 词法分析 worker
go func() {
defer wg.Done()
for job := range cp.lexerChan {
tokens := lexicalAnalysis(job.source)
cp.parserChan <- ParserJob{tokens: tokens, file: job.file}
}
}()
// 语法分析 worker
go func() {
defer wg.Done()
for job := range cp.parserChan {
ast := syntaxAnalysis(job.tokens)
cp.checkerChan <- CheckerJob{ast: ast, file: job.file}
}
}()
// 类型检查 worker
go func() {
defer wg.Done()
for job := range cp.checkerChan {
typedAst := typeCheck(job.ast)
cp.emitterChan <- EmitterJob{ast: typedAst, file: job.file}
}
}()
// 代码生成 worker
go func() {
defer wg.Done()
for job := range cp.emitterChan {
emit(job.ast, job.file)
}
}()
}
// 提交任务
for _, file := range files {
select {
case cp.lexerChan <- LexerJob{source: readFile(file), file: file}:
case <-ctx.Done():
return
}
}
close(cp.lexerChan)
wg.Wait()
}
技术对比分析
JavaScript/Node.js vs Go
typescript
// 当前 TypeScript 编译器的限制
interface CompilerLimitations {
singleThreaded: boolean; // 主要是单线程处理
memoryIntensive: boolean; // 内存使用较高
gcPressure: boolean; // GC 压力大
startupTime: number; // 启动时间长
}
const currentLimitations: CompilerLimitations = {
singleThreaded: true,
memoryIntensive: true,
gcPressure: true,
startupTime: 500 // ms
};
// Go 版本的优势
interface GoAdvantages {
nativeParallelism: boolean; // 原生并发支持
lowMemoryFootprint: boolean; // 低内存占用
fastStartup: boolean; // 快速启动
staticBinary: boolean; // 静态二进制文件
}
const goAdvantages: GoAdvantages = {
nativeParallelism: true,
lowMemoryFootprint: true,
fastStartup: true,
staticBinary: true
};
迁移策略
1. 渐进式重构
2. 兼容性保证
go
// Go 版本保持 API 兼容性
package typescript
import "C"
// 导出给 Node.js 的 C API
//export compile
func compile(source *C.char, options *C.char) *C.char {
goSource := C.GoString(source)
goOptions := C.GoString(options)
result := CompileTypeScript(goSource, goOptions)
return C.CString(result)
}
// 保持现有的 TypeScript API
func CompileTypeScript(source string, options string) string {
compiler := NewCompiler()
return compiler.Compile(source, ParseOptions(options))
}
//export getVersion
func getVersion() *C.char {
return C.CString("5.0.0-go")
}
func main() {} // 必需的 main 函数
预期收益
typescript
interface PerformanceGains {
category: string;
currentPerformance: string;
expectedImprovement: string;
impact: 'High' | 'Medium' | 'Low';
}
const expectedGains: PerformanceGains[] = [
{
category: "编译速度",
currentPerformance: "基准",
expectedImprovement: "3-10x 提升",
impact: "High"
},
{
category: "内存使用",
currentPerformance: "基准",
expectedImprovement: "50-70% 减少",
impact: "High"
},
{
category: "启动时间",
currentPerformance: "500ms",
expectedImprovement: "<50ms",
impact: "Medium"
},
{
category: "并发处理",
currentPerformance: "有限",
expectedImprovement: "原生支持",
impact: "High"
},
{
category: "部署便利性",
currentPerformance: "需要 Node.js",
expectedImprovement: "单一二进制文件",
impact: "Medium"
}
];
interface 和 type 的主要区别
基础语法差异
typescript
// Interface 声明
interface User {
id: number;
name: string;
email: string;
}
// Type 别名声明
type User = {
id: number;
name: string;
email: string;
};
1. 扩展能力对比
Interface 扩展
typescript
// Interface 继承
interface Animal {
name: string;
age: number;
}
interface Dog extends Animal {
breed: string;
bark(): void;
}
// 多重继承
interface Flyable {
fly(): void;
}
interface Swimmable {
swim(): void;
}
interface Duck extends Animal, Flyable, Swimmable {
quack(): void;
}
// Interface 声明合并
interface Window {
title: string;
}
interface Window {
ts: TypeScriptAPI;
}
// 合并后的 Window 接口
// interface Window {
// title: string;
// ts: TypeScriptAPI;
// }
Type 扩展
typescript
// Type 交叉类型
type Animal = {
name: string;
age: number;
};
type Dog = Animal & {
breed: string;
bark(): void;
};
// 复杂的交叉类型
type Flyable = {
fly(): void;
};
type Swimmable = {
swim(): void;
};
type Duck = Animal & Flyable & Swimmable & {
quack(): void;
};
// Type 不支持声明合并
// type Window = { title: string; };
// type Window = { ts: TypeScriptAPI; }; // Error: 重复标识符
2. 支持的类型范围
Interface 限制
typescript
// Interface 只能描述对象类型
interface StringArray {
[index: number]: string;
}
interface Function {
(x: number): number;
}
// Interface 不能描述原始类型、联合类型等
// interface StringOrNumber = string | number; // Error
// interface StringAlias = string; // Error
Type 的灵活性
typescript
// Type 可以描述任何类型
type StringOrNumber = string | number;
type StringAlias = string;
type NumberArray = number[];
type Tuple = [string, number, boolean];
// 联合类型
type Status = 'loading' | 'success' | 'error';
// 条件类型
type NonNullable<T> = T extends null | undefined ? never : T;
// 映射类型
type Partial<T> = {
[P in keyof T]?: T[P];
};
// 模板字面量类型
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<'click'>; // 'onClick'
// 函数类型
type Handler = (event: Event) => void;
type AsyncHandler = (event: Event) => Promise<void>;
// 复杂的工具类型
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
3. 计算属性和动态键
typescript
// Interface 中的计算属性
interface DynamicInterface {
[key: string]: any;
[key: number]: string;
}
// Type 中的更灵活的键类型
type DynamicKeys = 'name' | 'age' | 'email';
type DynamicType = {
[K in DynamicKeys]: string;
};
// 模板字面量键
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type UserGetters = Getters<{ name: string; age: number }>;
// {
// getName: () => string;
// getAge: () => number;
// }
4. 性能和编译差异
typescript
// Interface 的性能优势
interface LargeInterface {
prop1: string;
prop2: number;
// ... 100+ 属性
prop100: boolean;
}
// 继承时的性能
interface ExtendedInterface extends LargeInterface {
newProp: string;
}
// Type 的性能考虑
type LargeType = {
prop1: string;
prop2: number;
// ... 100+ 属性
prop100: boolean;
};
// 交叉类型的性能影响
type ExtendedType = LargeType & {
newProp: string;
};
// 复杂类型计算的性能影响
type ComplexType<T> = {
[K in keyof T]: T[K] extends string
? `processed_${T[K]}`
: T[K] extends number
? T[K] * 2
: T[K];
};
5. 实际使用场景对比
推荐使用 Interface 的场景
typescript
// 1. 定义对象的形状
interface ApiResponse {
data: any;
status: number;
message: string;
}
// 2. 类的契约
interface Drawable {
draw(): void;
}
class Circle implements Drawable {
draw() {
console.log('Drawing a circle');
}
}
// 3. 需要声明合并的场景
interface CustomWindow {
customProperty: string;
}
// 在其他文件中扩展
interface CustomWindow {
anotherProperty: number;
}
// 4. 公共 API 定义
interface PublicAPI {
version: string;
methods: {
get(path: string): Promise<any>;
post(path: string, data: any): Promise<any>;
};
}
推荐使用 Type 的场景
typescript
// 1. 联合类型
type Theme = 'light' | 'dark' | 'auto';
type Size = 'small' | 'medium' | 'large';
// 2. 工具类型和类型操作
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
type RequiredUser = Optional<User, 'email'>;
// 3. 条件类型
type ApiResult<T> = T extends string
? { message: T }
: T extends number
? { code: T }
: { data: T };
// 4. 复杂的类型计算
type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];
type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>;
// 5. 原始类型别名
type ID = string | number;
type Timestamp = number;
type JSONValue = string | number | boolean | null | JSONObject | JSONArray;
type JSONObject = { [key: string]: JSONValue };
type JSONArray = JSONValue[];
6. 错误信息差异
typescript
// Interface 错误信息
interface User {
name: string;
age: number;
}
const user: User = {
name: 'John',
// age: '25' // Error: Type 'string' is not assignable to type 'number'
};
// Type 错误信息
type UserType = {
name: string;
age: number;
};
const userType: UserType = {
name: 'John',
// age: '25' // Error: Type 'string' is not assignable to type 'number'
};
// 复杂类型的错误信息可能更难理解
type ComplexUser = User & { permissions: string[] } & { settings: object };
const complexUser: ComplexUser = {
name: 'John',
age: 25,
permissions: ['read'],
// settings: 'invalid' // 错误信息可能较长且复杂
};
选择建议
typescript
// 决策树
type TypeOrInterface<T> =
T extends 'object_shape' ? 'interface' :
T extends 'class_contract' ? 'interface' :
T extends 'declaration_merging' ? 'interface' :
T extends 'union_types' ? 'type' :
T extends 'computed_types' ? 'type' :
T extends 'primitive_alias' ? 'type' :
T extends 'complex_operations' ? 'type' :
'either'; // 两者都可以
// 最佳实践总结
interface BestPractices {
// 优先使用 interface 的情况
useInterface: [
'定义对象结构',
'类的实现契约',
'需要声明合并',
'公共 API 定义',
'简单的继承关系'
];
// 优先使用 type 的情况
useType: [
'联合类型',
'交叉类型',
'条件类型',
'映射类型',
'原始类型别名',
'复杂类型计算',
'工具类型定义'
];
// 性能考虑
performance: {
interface: '继承性能更好,错误信息更清晰';
type: '复杂类型计算可能影响编译性能';
};
}
any vs unknown vs never
any - 类型系统的逃生舱
typescript
// any 的特点:关闭类型检查
let anyValue: any = 42;
// 可以赋值为任何类型
anyValue = 'hello';
anyValue = true;
anyValue = { name: 'John' };
anyValue = [1, 2, 3];
anyValue = () => console.log('function');
// 可以访问任何属性(即使不存在)
console.log(anyValue.foo.bar.baz); // 不会报错,但运行时可能出错
// 可以调用任何方法
anyValue.nonExistentMethod(); // 不会报错,但运行时出错
// 可以作为任何类型使用
const str: string = anyValue; // 不会报错
const num: number = anyValue; // 不会报错
const obj: { name: string } = anyValue; // 不会报错
any 的使用场景
typescript
// 1. 迁移 JavaScript 代码
function legacyFunction(data: any) {
// 逐步添加类型
return data;
}
// 2. 第三方库没有类型定义
declare const thirdPartyLib: any;
thirdPartyLib.someMethod();
// 3. 动态内容(但通常有更好的替代方案)
function processJson(json: string): any {
return JSON.parse(json);
}
// 4. 复杂的类型操作(临时使用)
function complexTransform(input: any): any {
// 复杂的数据转换逻辑
return input;
}
any 的问题和风险
typescript
// 类型安全丢失
function dangerousFunction(value: any) {
// 这些操作都不会报错,但可能在运行时失败
return value.toUpperCase().split('').reverse().join('');
}
// 运行时错误
// dangerousFunction(123); // TypeError: value.toUpperCase is not a function
// dangerousFunction(null); // TypeError: Cannot read property 'toUpperCase' of null
// 智能提示丢失
let anyObj: any = { name: 'John', age: 30 };
// 没有智能提示,容易拼写错误
anyObj.naem; // 应该是 name,但不会报错
// 重构困难
function updateUser(user: any) {
user.name = 'Updated';
// 如果 User 接口改变,这里不会得到提示
}
unknown - 类型安全的 any
typescript
// unknown 的特点:类型安全的顶级类型
let unknownValue: unknown = 42;
// 可以赋值为任何类型
unknownValue = 'hello';
unknownValue = true;
unknownValue = { name: 'John' };
unknownValue = [1, 2, 3];
// 但不能直接使用
// console.log(unknownValue.length); // Error: Object is of type 'unknown'
// unknownValue.toUpperCase(); // Error: Object is of type 'unknown'
// unknownValue(); // Error: Object is of type 'unknown'
// 需要类型检查后才能使用
if (typeof unknownValue === 'string') {
console.log(unknownValue.length); // OK: TypeScript 知道这里是 string
console.log(unknownValue.toUpperCase()); // OK
}
if (Array.isArray(unknownValue)) {
console.log(unknownValue.length); // OK: TypeScript 知道这里是数组
unknownValue.push(4); // OK
}
unknown 的类型守卫
typescript
// 类型守卫函数
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function isNumber(value: unknown): value is number {
return typeof value === 'number';
}
function isObject(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
// 使用类型守卫
function processUnknown(value: unknown) {
if (isString(value)) {
return value.toUpperCase(); // TypeScript 知道这里是 string
}
if (isNumber(value)) {
return value * 2; // TypeScript 知道这里是 number
}
if (isObject(value)) {
return Object.keys(value); // TypeScript 知道这里是 object
}
throw new Error('Unsupported type');
}
// 更复杂的类型守卫
interface User {
name: string;
age: number;
}
function isUser(value: unknown): value is User {
return (
isObject(value) &&
'name' in value &&
'age' in value &&
typeof value.name === 'string' &&
typeof value.age === 'number'
);
}
function processUser(data: unknown) {
if (isUser(data)) {
console.log(`User: ${data.name}, Age: ${data.age}`); // 类型安全
} else {
throw new Error('Invalid user data');
}
}
unknown 的实际应用
typescript
// 1. API 响应处理
async function fetchData(url: string): Promise<unknown> {
const response = await fetch(url);
return response.json(); // JSON.parse 返回 any,但我们用 unknown 更安全
}
// 安全的数据处理
async function getUserData(userId: string) {
const data = await fetchData(`/api/users/${userId}`);
if (isUser(data)) {
return data; // 类型安全的 User
}
throw new Error('Invalid user data received');
}
// 2. 错误处理
function handleError(error: unknown) {
if (error instanceof Error) {
console.error('Error message:', error.message);
console.error('Stack trace:', error.stack);
} else if (typeof error === 'string') {
console.error('String error:', error);
} else {
console.error('Unknown error:', error);
}
}
try {
// 一些可能抛出任何类型错误的代码
riskyOperation();
} catch (error) {
handleError(error); // error 是 unknown 类型
}
// 3. 配置对象验证
interface Config {
apiUrl: string;
timeout: number;
retries: number;
}
function isConfig(value: unknown): value is Config {
return (
isObject(value) &&
'apiUrl' in value &&
'timeout' in value &&
'retries' in value &&
typeof value.apiUrl === 'string' &&
typeof value.timeout === 'number' &&
typeof value.retries === 'number'
);
}
function loadConfig(configData: unknown): Config {
if (isConfig(configData)) {
return configData;
}
throw new Error('Invalid configuration');
}
never - 永不存在的类型
typescript
// never 的特点:表示永远不会发生的类型
// 1. 永远不会返回的函数
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {
// 无限循环
}
}
// 2. 不可能的联合类型
type Impossible = string & number; // never,因为没有值既是 string 又是 number
// 3. 穷尽性检查
type Color = 'red' | 'green' | 'blue';
function getColorName(color: Color): string {
switch (color) {
case 'red':
return 'Red';
case 'green':
return 'Green';
case 'blue':
return 'Blue';
default:
// 如果所有情况都处理了,这里的 color 类型是 never
const exhaustiveCheck: never = color;
return exhaustiveCheck; // 这行永远不会执行
}
}
// 如果添加新的颜色但忘记处理,TypeScript 会报错
type ExtendedColor = 'red' | 'green' | 'blue' | 'yellow';
function getExtendedColorName(color: ExtendedColor): string {
switch (color) {
case 'red':
return 'Red';
case 'green':
return 'Green';
case 'blue':
return 'Blue';
default:
// Error: Type 'string' is not assignable to type 'never'
// 因为 'yellow' 没有被处理
const exhaustiveCheck: never = color;
return exhaustiveCheck;
}
}
never 的高级应用
typescript
// 1. 条件类型中的 never
type NonNullable<T> = T extends null | undefined ? never : T;
type Result1 = NonNullable<string | null>; // string
type Result2 = NonNullable<number | undefined>; // number
type Result3 = NonNullable<null>; // never
// 2. 映射类型中的 never
type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];
type Example = {
name: string;
age: number;
getName: () => string;
setAge: (age: number) => void;
};
type FuncNames = FunctionPropertyNames<Example>; // 'getName' | 'setAge'
// 3. 过滤类型
type FilterOut<T, U> = T extends U ? never : T;
type WithoutStrings = FilterOut<string | number | boolean, string>; // number | boolean
// 4. 递归类型中的终止条件
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object
? T[P] extends Function
? T[P]
: DeepReadonly<T[P]>
: T[P];
};
// 5. 类型安全的断言
function assertNever(value: never): never {
throw new Error(`Unexpected value: ${value}`);
}
type Status = 'loading' | 'success' | 'error';
function handleStatus(status: Status) {
switch (status) {
case 'loading':
return 'Loading...';
case 'success':
return 'Success!';
case 'error':
return 'Error occurred';
default:
return assertNever(status); // 确保所有情况都被处理
}
}
三者对比总结
typescript
// 类型安全性对比
interface TypeSafetyComparison {
any: {
safety: 'None'; // 完全关闭类型检查
usage: 'Direct'; // 可以直接使用
errors: 'Runtime'; // 错误在运行时发现
migration: 'Easy'; // 容易从 JS 迁移
};
unknown: {
safety: 'High'; // 类型安全
usage: 'Guarded'; // 需要类型守卫
errors: 'Compile-time'; // 错误在编译时发现
migration: 'Gradual'; // 渐进式类型化
};
never: {
safety: 'Absolute'; // 绝对类型安全
usage: 'Impossible'; // 不能有值
errors: 'Compile-time'; // 编译时检查
purpose: 'Type-level'; // 类型级别的逻辑
};
}
// 使用场景总结
type UsageRecommendations = {
any: [
'迁移遗留 JavaScript 代码',
'第三方库缺少类型定义',
'快速原型开发(临时使用)',
'复杂类型操作的临时解决方案'
];
unknown: [
'API 响应处理',
'用户输入验证',
'错误处理',
'配置对象验证',
'类型安全的 JSON 解析',
'替代 any 的更安全选择'
];
never: [
'穷尽性检查',
'不可达代码标记',
'条件类型中的排除',
'类型级别的逻辑控制',
'函数永不返回的标记'
];
};
// 最佳实践
const bestPractices = {
avoidAny: '尽量避免使用 any,它会破坏 TypeScript 的类型安全',
preferUnknown: '当类型不确定时,优先使用 unknown 而不是 any',
useNever: '利用 never 进行穷尽性检查,确保代码的完整性',
gradualTyping: '从 any 逐步迁移到具体类型或 unknown',
typeGuards: '为 unknown 类型编写类型守卫函数'
} as const;
实际项目中的应用示例
typescript
// 综合示例:类型安全的数据处理管道
class DataProcessor {
// 使用 unknown 接收不确定的数据
async processData(rawData: unknown): Promise<ProcessedData> {
// 验证数据格式
if (!this.isValidInput(rawData)) {
// 使用 never 标记不可能的情况
return this.handleInvalidData(rawData);
}
// 类型安全的处理
return this.transformData(rawData);
}
private isValidInput(data: unknown): data is RawData {
return (
typeof data === 'object' &&
data !== null &&
'id' in data &&
'content' in data
);
}
private handleInvalidData(data: unknown): never {
throw new Error(`Invalid data format: ${JSON.stringify(data)}`);
}
private transformData(data: RawData): ProcessedData {
// 类型安全的数据转换
return {
id: data.id,
processedContent: data.content.toUpperCase(),
timestamp: Date.now()
};
}
}
interface RawData {
id: string;
content: string;
}
interface ProcessedData {
id: string;
processedContent: string;
timestamp: number;
}
通过理解 any
、unknown
和 never
的区别和适用场景,我们可以编写更加类型安全和健壮的 TypeScript 代码。