如何在判别字段存在重叠时收窄对象类型联合?
解决TypeScript联合类型switch收窄失效的问题
你遇到的问题核心是:第三个Animal分支的kind是宽泛的string类型,它包含了'cat'、'dog'这些字面量值,所以TypeScript无法确定当animal.kind === 'cat'时,这个对象一定不是第三个分支,导致params的类型没法精准收窄。
下面是两种可行的解决方法:
方法一:修改类型定义,缩小第三个分支的kind范围
把第三个分支的kind改成排除'cat'和'dog'的字符串类型,让TypeScript明确知道'cat'、'dog'不会出现在第三个分支里:
type Animal = { kind: 'cat'; params: string; } | { kind: 'dog'; params: number[]; } | { kind: Exclude<string, 'cat' | 'dog'>; params: Record<string, string> }
修改后再用原来的switch语句,TypeScript就能正确识别每个case里的params类型了。
方法二:使用类型守卫(不修改原类型)
如果不想改动原类型,可以写一个自定义类型守卫函数,帮TypeScript精准判断类型:
// 类型守卫函数,判断是否为cat类型 function isCat(animal: Animal): animal is Extract<Animal, { kind: 'cat' }> { return animal.kind === 'cat'; } // 使用类型守卫 if (isCat(animal)) { console.log(animal.params.toUpperCase()); // 这里params确定是string类型 } else if (animal.kind === 'dog') { console.log(animal.params.length); // params是number[]类型 } else { console.log("animal is an object"); // params是Record<string, string>类型 }
如果坚持要用switch语句,也可以在case里用类型断言(注意:这种方式需要你自己保证类型安全):
switch (animal.kind) { case 'cat': console.log((animal as { kind: 'cat'; params: string }).params.toUpperCase()) break; case 'dog': console.log((animal as { kind: 'dog'; params: number[] }).params.length) break; default: console.log("animal is an object"); }
内容的提问来源于stack exchange,提问作者Shnd
相关产品推荐
相关产品推荐

