TypeScript创建映射类型时ReturnType失效?RawPerson推导为unknown问题
类型推导异常的核心原因
- 泛型作用域遮蔽是头号诱因
你当前的all实现存在关键的泛型冲突:外层函数声明了泛型<T>,用于接收调用时传入的具体类型(比如number、string);但返回的内层箭头函数前,你又重复声明了一个同名的<T>。TS的泛型是块级作用域的,这个内层的同名T会完全遮蔽外层的T,和你调用all时传入的类型没有任何关联。最终返回的是一个完全独立、未绑定任何具体类型的泛型函数,TS在没有上下文指定这个内层T的类型时,会默认将其推导为unknown。 - Struct接口定义与实际返回值不匹配
你定义的Struct索引签名要求每个字段都是可独立接收泛型参数的函数<T>(input: string) => T | DiplomacyError>,而非绑定了具体返回类型的普通函数。这种定义下,TS会认为每个字段的返回类型取决于调用时临时传入的泛型参数,没有固定的确定值。 - ReturnType的提取逻辑限制
ReturnType是基于函数已实例化、确定的返回值标注提取类型的。如果传入ReturnType的是未绑定泛型参数的泛型函数类型,TS没有足够的信息推导泛型对应的真实类型,最终只能返回unknown,这也是你看到推导结果全是unknown的直接表现。
修复方案
按以下步骤调整即可恢复预期的类型推导效果:
- 修正
all函数的泛型声明
删除内层返回函数前重复声明的<T>,直接复用外层已经绑定的泛型T,修改后的实现如下:
调整后,当你调用export const all = <T>(typifier: Typifier<T>, ...assertions: Assertor[]) => // 去掉此处冗余的<T>声明,直接使用外层的T作为返回值的类型标注 (input: string): T | DiplomacyError => { const parsedInput = typifier(input); if (parsedInput === "#!CD") { return "#!CD" as DiplomacyError; } for (let i = 0; i < assertions.length; i++) { if (assertions[i](parsedInput) === "#!CD") { return "#!CD" as DiplomacyError; } } // 类型匹配后无需双重断言,直接返回即可 return parsedInput; };all<number>(isInteger, isNonNegative)时,得到的是一个完全固定了T为number的普通函数,类型为(input: string) => number | DiplomacyError,不再是待实例化的泛型函数。 - 调整
Struct接口的定义
移除索引签名中函数的冗余泛型参数,匹配修改后的返回函数类型:export interface Struct { // 去掉函数前的<T>,每个字段为已绑定返回类型的普通函数 [key: string]: (input: string) => unknown; } - 最终推导效果
完成上述修改后,Person对象的字段类型为:age:(input: string) => number | DiplomacyErrorname:(input: string) => string | DiplomacyError
此时RawType<typeof Person>会正确推导出你预期的RawPerson结构:
type RawPerson = { age: number | DiplomacyError, name: string | DiplomacyError }
内容的提问来源于stack exchange,提问作者Davide Valdo
相关产品推荐
相关产品推荐

