TypeScript在条件块中为何无法正确推断泛型类型的属性?
问题原因
TypeScript 目前不支持通过判断泛型参数的取值,自动收窄对应的条件类型结果。你虽然已经确认type的值为DataType.Bar,但 TS 不会联动把泛型T收窄为DataType.Bar,因此对应的Data<T>也不会自动收窄为BarData,依旧是联合类型FooData | BarData,所以无法直接访问BarData独有的属性。
解决方案
下面提供三种常用的修正方案,可根据项目场景选择:
1. 类型断言(最简单快速)
已经确认运行时逻辑正确的前提下,直接给data做类型断言即可:
if (type === DataType.Bar) { const barData = data as BarData; console.log(barData.otherKey) // getter调用也可以对key做断言解决报错 console.log(getter('otherKey' as keyof Data<T>)) }
2. 自定义类型守卫(更安全)
封装类型守卫函数,同时关联type和data的类型判断,收窄逻辑更严谨:
// 新增类型守卫 function isBarData<T extends DataType>(type: T, data: Data<T>): data is BarData { return type === DataType.Bar } function func<T extends DataType>(type: T, data: Data<T>): void { const getter = <K extends keyof Data<T>>(key: K): Data<T>[K] => data[key] if (isBarData(type, data)) { // 这里data已经被自动收窄为BarData console.log(data.otherKey) console.log(getter('otherKey' as keyof Data<T>)) } }
3. 函数重载(最丝滑,无需额外断言)
如果可以调整函数定义,改用重载写法,TS 对固定参数组合的收窄支持更好:
enum DataType { Foo, Bar } interface FooData { someKey: string } interface BarData extends FooData { otherKey: string } // 重载签名 function func(type: DataType.Foo, data: FooData): void function func(type: DataType.Bar, data: BarData): void // 实现签名 function func(type: DataType, data: FooData | BarData): void { const getter = <K extends keyof typeof data>(key: K) => data[key] if (type === DataType.Bar) { console.log(data.otherKey) // 无报错,自动推导为BarData console.log(getter('otherKey')) // 无报错 } }
内容的提问来源于stack exchange,提问作者DustInComp
相关产品推荐
相关产品推荐

