TypeScript中createConfig函数泛型类型推断错误的原因与解决方法
问题原因
- 类型映射逻辑反向
你当前的Schema<T>定义逻辑是「基于最终的配置类型T,定义对应的Schema结构」,但你调用createConfig时是先传入Schema对象,需要TS从Schema对象反向推导出最终的配置类型T,原有类型定义没有适配这种反向推导的场景,TS只能将传入的Schema对象的结构本身当作T的结构进行推导,自然会把default、optional这些Schema层的属性当作T的字段属性。 - 类型推导匹配失败导致的异常拓宽
泛型匹配失败时TS会对原始类型做异常拓宽,boolean作为原始类型的原型上存在valueOf方法,匹配不到正确类型时就会被推断为包含valueOf的对象结构,也就是你看到的{valueOf}异常结果。 - 你写的预期结果大概率存在笔误,正常
Config<T>的结构应该是最终的配置对象,即{testProp: boolean},如果确实需要保留default、optional字段,可自行调整下方推导逻辑。
修复方案
第一步:新增反向推导工具类型
定义工具类型从传入的Schema结构直接推导出最终的配置类型:
// 从Schema结构推导最终配置类型的工具类型 type InferConfigFromSchema<S> = { // 处理可选字段 [P in keyof S as S[P]['optional'] extends true ? P : never]?: S[P] extends SchemaObj<infer U> ? U : S[P] extends object ? InferConfigFromSchema<S[P]> : never } & { // 处理必选字段 [P in keyof S as S[P]['optional'] extends true ? never : P]: S[P] extends SchemaObj<infer U> ? U : S[P] extends object ? InferConfigFromSchema<S[P]> : never // 抹平交叉类型的冗余结构,让类型展示更友好 } extends infer O ? { [K in keyof O]: O[K] } : never
第二步:调整createConfig函数的泛型定义
修改函数的泛型约束,优先适配从入参反向推导返回值类型的场景:
// 泛型S约束入参的Schema结构,返回值通过工具类型自动推导 function createConfig<S extends Record<string, any>>( schema: S, opts?: ConfigOptions ): Config<InferConfigFromSchema<S>> { // 原有函数的实现逻辑完全不需要改动 }
可选:保留原有正向类型校验能力
如果需要保留Schema<T>的正向校验能力(即提前定义好配置类型T,约束传入的Schema必须符合T的结构),可以修改函数定义为双向约束:
function createConfig<T, S extends Schema<T> = Schema<T>>( schema: S, opts?: ConfigOptions ): Config<T> { // 原有实现不变 }
修改后调用你给出的示例代码,TS会自动推导出config的类型为{ testProp?: boolean },符合预期。
内容的提问来源于stack exchange,提问作者nidomiro
相关产品推荐
相关产品推荐

