TypeScript重载函数switch case报错,如何规避额外类型检查?
TypeScript联合类型函数重载的类型收窄优化
先看你遇到的问题:
原代码如下:
interface First { a: number } interface Second { b: number } type GeneralInterface = First | Second; type Kind = 'First' | 'Second'; function getValue(kind: 'First', object: First): number function getValue(kind: 'Second', object: Second): number function getValue(kind: Kind, object: GeneralInterface): number { switch (kind) { case "First": { return object.a } case "Second": { return object.b } } }
运行时触发TS错误:
TS2339: Property 'a' does not exist on type 'GeneralInterface'. Property 'a' does not exist on type 'Second'.
当前的解决办法是加额外的in检查,但这会让代码变啰嗦,复杂接口场景下工作量还大。既然你确定参数组合只有指定的两种,有几个更优雅的方案:
方案1:直接使用类型断言
既然明确参数组合合法,在实现里直接用类型断言告诉TypeScript当前分支的object类型:
interface First { a: number } interface Second { b: number } type GeneralInterface = First | Second; type Kind = 'First' | 'Second'; function getValue(kind: 'First', object: First): number function getValue(kind: 'Second', object: Second): number function getValue(kind: Kind, object: GeneralInterface): number { switch (kind) { case "First": { return (object as First).a; } case "Second": { return (object as Second).b; } } }
这种方式最简单,完全不需要额外检查,适合你确定参数合法的场景。
方案2:自定义类型守卫
如果想兼顾类型安全和可读性,可以写一个简单的类型守卫函数,把类型判断逻辑抽离出来:
interface First { a: number } interface Second { b: number } type GeneralInterface = First | Second; type Kind = 'First' | 'Second'; function isFirst(kind: Kind, obj: GeneralInterface): obj is First { return kind === 'First'; } function isSecond(kind: Kind, obj: GeneralInterface): obj is Second { return kind === 'Second'; } function getValue(kind: 'First', object: First): number function getValue(kind: 'Second', object: Second): number function getValue(kind: Kind, object: GeneralInterface): number { if (isFirst(kind, object)) { return object.a; } else if (isSecond(kind, object)) { return object.b; } throw new Error(`Invalid argument: ${kind}`); }
类型守卫会让TypeScript自动收窄类型,复杂场景下还能复用守卫逻辑,代码更整洁。
方案3:重构为区分联合类型参数
把kind和object合并成一个参数,让TypeScript自动关联类型,彻底避免手动类型判断:
interface First { kind: 'First', a: number } interface Second { kind: 'Second', b: number } type GeneralInterface = First | Second; function getValue(obj: GeneralInterface): number { switch (obj.kind) { case "First": { return obj.a; } case "Second": { return obj.b; } } }
这种方式是TypeScript推荐的区分联合类型写法,TypeScript能完美识别每个分支的类型,代码最简洁,连函数重载都不需要了。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

