如何让TypeScript通过嵌套type.name正确推断联合类型对象?
问题:TypeScript嵌套字段
type.name无法触发类型守卫 尝试通过判断嵌套的type.name字段,让TypeScript在switch语句中推断对象的正确类型,但无法实现类型守卫;直接判断顶层name字段时则能正常工作。希望通过type.name的值让TS识别对象可访问的属性,已知as类型断言或平铺对象的解决方案,寻求其他替代方案。
代码示例
interface Base { id: number; name: "a" | "b" | "c" | "d"; // 此处类型守卫正常工作 type: { id: number; name: "a" | "b" | "c" | "d"; // 此处类型守卫无法正常工作 } } interface A extends Base { name: "a"; type: { id: number; name: "a"; } a: { b: number; } } interface B extends Base { name: "b"; type: { id: number; name: "b"; } b: { a: number; } } interface Generic extends Base { name: "c" | "d"; type: { id: number; name: "c" | "d"; } } type C = A | B | Generic function test(t: C) { // 如果将switch条件改为't.name'则正常工作 switch(t.type.name) { // switch(t.name) { case "a": // 期望推断为A类型,但当前无法实现 console.log(t.a) break; case "c": console.log(t.name); break; case "b": // 期望推断为B类型,但当前无法实现 console.log(t.b); break; } }
解决方案
1. 自定义类型守卫函数
编写专门的类型守卫函数,明确判断type.name并返回类型断言,让TypeScript识别对象类型:
function isA(t: C): t is A { return t.type.name === "a"; } function isB(t: C): t is B { return t.type.name === "b"; } function test(t: C) { switch(t.type.name) { case "a": if (isA(t)) { console.log(t.a); // 正确推断为A类型 } break; case "b": if (isB(t)) { console.log(t.b); // 正确推断为B类型 } break; case "c": console.log(t.name); break; } }
2. 重构类型定义,让type成为可辨识联合
调整类型结构,将type字段定义为联合类型,使其成为可辨识联合的一部分,这样TypeScript能直接通过type.name触发类型守卫:
// 先定义独立的type联合类型 type TypeA = { id: number; name: "a" }; type TypeB = { id: number; name: "b" }; type TypeGeneric = { id: number; name: "c" | "d" }; // 用泛型Base关联name和type的类型 interface Base<T> { id: number; name: T extends TypeA ? "a" : T extends TypeB ? "b" : "c" | "d"; type: T; } interface A extends Base<TypeA> { a: { b: number }; } interface B extends Base<TypeB> { b: { a: number }; } interface Generic extends Base<TypeGeneric> {} type C = A | B | Generic function test(t: C) { switch(t.type.name) { case "a": console.log(t.a); // 自动推断为A类型 break; case "b": console.log(t.b); // 自动推断为B类型 break; case "c": console.log(t.name); break; } }
3. 结合多字段判断触发类型推断
利用TypeScript的交叉类型推断特性,同时判断name和type.name字段(因为A/B类型中这两个字段值一致),让TS自动识别对象类型:
function test(t: C) { switch(t.type.name) { case "a": if (t.name === "a") { console.log(t.a); // 推断为A类型 } break; case "b": if (t.name === "b") { console.log(t.b); // 推断为B类型 } break; case "c": console.log(t.name); break; } }
内容的提问来源于stack exchange,提问作者CanIHazCookieNow
相关产品推荐
相关产品推荐

