TypeScript中函数无法自动推断映射类型问题求助
问题描述
我定义了一组基于枚举的请求/响应函数,但TypeScript无法自动推断getT1和getT3的返回类型,只有显式指定泛型参数时才能得到正确结果。我希望调用getT1或getT3时不用手动指定泛型,就能自动获得对应枚举值的响应类型,但目前返回的是所有响应类型的联合类型。
代码示例:
declare function getT1<T extends Type>(req: Req1[T]): Res[T]; declare function getT2<T extends Type>(req: Req2<T>): Res[T]; declare function getT3<T extends Type>(req: Req3<T>): Res[T]; enum Type { A, B, C, } type Req1 = { [Type.A]: { ra: string, type: Type.A }, [Type.B]: { rb: string, type: Type.B }, [Type.C]: { rc: string, type: Type.C } } type Req2<T extends Type> = { type: T, r: string, } type Req3<T extends Type> = Req1[T]; type Res = { [Type.A]: { a: string }, [Type.B]: { b: string }, [Type.C]: { c: string } } // 报错:期望自动推断返回类型为 {a: string} const a: { a: string } = getT1({ type: Type.A, ra: '' }); // 正常工作:显式指定泛型 const aa: { a: string } = getT1<Type.A>({ type: Type.A, ra: '' }); // 自动推断正常 const a2: { a: string } = getT2({ type: Type.A, r: '' }); const aa2: { a: string } = getT2<Type.A>({ type: Type.A, r: '' }); // 报错:同getT1 const a3: { a: string } = getT3({ type: Type.A, ra: '' }); // 正常工作:显式指定泛型 const aa3: { a: string } = getT3<Type.A>({ type: Type.A, ra: '' });
原因分析
getT2能自动推断泛型,而getT1/getT3不行,核心差异在于请求类型的定义方式:
Req2<T>是泛型类型,直接将type字段与泛型参数T绑定,TypeScript可以通过传入对象的type值反向推断出T的具体类型。Req1[T]是索引访问类型,传入的参数会被推断为Req1所有属性的联合类型(即Req1[Type.A] | Req1[Type.B] | Req1[Type.C]),此时泛型T无法被唯一确定,只能推断为Type全集,导致返回类型变成所有响应的联合类型。Req3<T>本质和Req1[T]等价,因此遇到同样的推断问题。
解决方案
以下三种方案都能实现自动推断泛型的需求,可根据代码结构选择:
方案1:函数重载定义
为每个枚举值单独定义函数重载,让TypeScript根据参数匹配对应重载,自动推断返回类型:
// 为Type的每个枚举值定义重载 declare function getT1(req: Req1[Type.A]): Res[Type.A]; declare function getT1(req: Req1[Type.B]): Res[Type.B]; declare function getT1(req: Req1[Type.C]): Res[Type.C]; // 通用实现签名(仅用于类型检查,实际函数逻辑写在这里) declare function getT1(req: Req1[keyof Req1]): Res[keyof Res]; // getT3同理 declare function getT3(req: Req1[Type.A]): Res[Type.A]; declare function getT3(req: Req1[Type.B]): Res[Type.B]; declare function getT3(req: Req1[Type.C]): Res[Type.C]; declare function getT3(req: Req1[keyof Req1]): Res[keyof Res];
方案2:泛型绑定约束
通过交叉类型强制参数的type字段与泛型T绑定,触发TypeScript的反向推断:
declare function getT1<T extends Type>(req: { type: T } & Req1[T]): Res[T]; declare function getT3<T extends Type>(req: { type: T } & Req1[T]): Res[T];
方案3:重构Req1为泛型类型
将Req1改为泛型条件类型,对齐Req2的结构:
type Req1<T extends Type> = T extends Type.A ? { ra: string, type: Type.A } : T extends Type.B ? { rb: string, type: Type.B } : T extends Type.C ? { rc: string, type: Type.C } : never; // 此时getT1的定义可与getT2完全一致 declare function getT1<T extends Type>(req: Req1[T]): Res[T];
验证效果
使用任意一种方案后,原本报错的代码都能自动推断正确的返回类型:
// 现在正常工作,自动推断返回类型为 {a: string} const a: { a: string } = getT1({ type: Type.A, ra: '' }); const a3: { a: string } = getT3({ type: Type.A, ra: '' });
内容的提问来源于stack exchange,提问作者Tubc
相关产品推荐
相关产品推荐

