TypeScript类型守卫与可辨识联合详解二
接上文
原理分析
类型守卫的原理
TypeScript 编译器通过控制流分析(Control Flow Analysis)来实现类型守卫:
控制流分析:TypeScript 分析代码的执行路径
类型收窄:在特定代码路径中,将宽泛的类型收窄为更具体的类型
作用域感知:类型信息只在相应的作用域内有效
function example(value: string | number) {// 这里 value 是 string | numberif (typeof value === "string") {// 这里 value 被收窄为 stringconsole.log(value.length);} else {// 这里 value 被收窄为 numberconsole.log(value.toFixed(2));}// 离开条件语句后,value 恢复为 string | number
}可辨识联合的原理
可辨识联合基于以下机制工作:
共同判别式:所有联合成员都有一个共同的字段(通常是字面量类型)
互斥性:判别式的值在所有联合成员中是互斥的
穷尽性检查:TypeScript 可以检查是否处理了所有可能的情况
type Result<T, E> = | { success: true; data: T }| { success: false; error: E };function handleResult<T, E>(result: Result<T, E>) {if (result.success) {// result 被识别为成功的情况,可以访问 dataconsole.log("Data:", result.data);} else {// result 被识别为失败的情况,可以访问 errorconsole.log("Error:", result.error);}
}高级用法
结合类型守卫和可辨识联合
// 自定义类型守卫与可辨识联合结合
function isCircle(shape: Shape): shape is { kind: "circle"; radius: number } {return shape.kind === "circle";
}function isSquare(shape: Shape): shape is { kind: "square"; sideLength: number } {return shape.kind === "square";
}function processShapes(shapes: Shape[]) {const circles = shapes.filter(isCircle);const squares = shapes.filter(isSquare);circles.forEach(circle => {console.log("Circle area:", Math.PI * circle.radius ** 2);});squares.forEach(square => {console.log("Square area:", square.sideLength ** 2);});
}复杂的可辨识联合
// 更复杂的例子:表单状态管理
type FormState =| { status: "idle" }| { status: "validating" }| { status: "submitting" }| { status: "success"; message: string }| { status: "error"; errors: string[] };function getFormMessage(state: FormState): string {switch (state.status) {case "idle":return "Please fill out the form";case "validating":return "Validating...";case "submitting":return "Submitting...";case "success":return state.message; // 可以访问 messagecase "error":return `Errors: ${state.errors.join(", ")}`; // 可以访问 errorsdefault:const _exhaustiveCheck: never = state;return _exhaustiveCheck;}
}总结
类型守卫和可辨识联合是 TypeScript 类型系统的强大特性:
类型守卫:通过运行时检查在编译时提供类型安全
可辨识联合:通过共享字段实现精确的类型区分
组合使用:两者结合可以提供更强的类型安全和更好的开发体验
这些特性让 TypeScript 能够在编译时捕获更多潜在错误,同时提供更好的开发工具支持(如自动补全和代码导航)。
