TypeScript条件类型下无法正确推断类型问题咨询
TypeScript条件类型关联推断失败问题分析
我为useStrategy的options参数与toPayload的参数使用了相同的泛型类型Options<ST extends SwitchType>,期望TypeScript能正确推断toPayload的参数类型,但收到错误提示:
参数类型“FirstOptions | SecondOptions”无法赋值给参数类型“FirstOptions”。类型“SecondOptions”缺少“FirstOptions”中必需的属性“b”(2345)
请问这是TypeScript的已知限制,还是我在用法上存在疏漏?相关代码如下:
enum SwitchType { First = 'first', Second = 'second' } export type FirstOptions = { a: string b: number } type SecondOptions = { a: string } export type Options<ST extends SwitchType> = ST extends SwitchType.Second ? SecondOptions : ST extends SwitchType.First ? FirstOptions : never type Strategy<ST> = ST extends SwitchType.Second ? SecondStrategy : ST extends SwitchType.First ? FirstStrategy : never type ToPayloadFunction<ST extends SwitchType> = ( options: Options<ST> ) => any type FirstStrategy = { toPayload: ToPayloadFunction<SwitchType.First> } type SecondStrategy = { toPayload: ToPayloadFunction<SwitchType.Second> } const getStrategy = <ST extends SwitchType>(type: ST): Strategy<ST> => { const firstStrategy: FirstStrategy = { toPayload: (options) => { console.log(options) } } const secondStrategy: SecondStrategy = { toPayload: (options) => { console.log(options) } } if(type === SwitchType.Second) return secondStrategy as any if(type === SwitchType.First) return firstStrategy as any throw new Error('error') } const useStrategy = <ST extends SwitchType>(type: ST, options: Options<ST>): void => { const { toPayload } = getStrategy(type) // Argument of type 'FirstOptions | SecondOptions' is not assignable to parameter of type 'FirstOptions'. // Property 'b' is missing in type 'SecondOptions' but required in type 'FirstOptions' toPayload(options) }
问题原因
这是TypeScript的已知限制,核心在于TypeScript对泛型条件类型的关联性追踪能力不足:
- 调用
getStrategy(type)时,返回的Strategy<ST>是条件类型,TypeScript无法将其与options的Options<ST>建立精确的一对一关联,反而会把Strategy<ST>展开为FirstStrategy | SecondStrategy联合类型。 - 对于函数联合类型,TypeScript要求传入的参数必须满足联合类型中所有函数的参数要求。
FirstOptions | SecondOptions显然无法同时满足FirstOptions(必须有b属性)和SecondOptions(无b属性)的要求,因此触发报错。
解决方案
方案1:添加类型断言明确关联
通过类型断言让TypeScript明确toPayload的参数类型与options完全匹配:
const useStrategy = <ST extends SwitchType>(type: ST, options: Options<ST>): void => { const { toPayload } = getStrategy(type) as { toPayload: (options: Options<ST>) => any }; toPayload(options); };
方案2:重构类型简化关联
避免嵌套的条件类型,直接将Strategy定义为泛型对象,让TypeScript能更好地追踪类型关联:
enum SwitchType { First = 'first', Second = 'second' } export type FirstOptions = { a: string b: number } type SecondOptions = { a: string } export type Options<ST extends SwitchType> = ST extends SwitchType.Second ? SecondOptions : ST extends SwitchType.First ? FirstOptions : never // 直接定义泛型Strategy类型 type Strategy<ST extends SwitchType> = { toPayload: (options: Options<ST>) => any } const getStrategy = <ST extends SwitchType>(type: ST): Strategy<ST> => { if (type === SwitchType.Second) { return { toPayload: (options: SecondOptions) => { console.log(options); } } as Strategy<ST>; } if (type === SwitchType.First) { return { toPayload: (options: FirstOptions) => { console.log(options); } } as Strategy<ST>; } throw new Error('error'); } const useStrategy = <ST extends SwitchType>(type: ST, options: Options<ST>): void => { const { toPayload } = getStrategy(type); toPayload(options); // 类型推断正常 };
内容的提问来源于stack exchange,提问作者Tommaso Carnemolla
相关产品推荐
相关产品推荐

