为何签名中的泛型会破坏TypeScript类型推断?
问题解决:保留泛型默认值时修复TypeScript类型推断失效
问题背景
移除xx函数的泛型定义后,TypeScript类型推断正常;但保留xx<T>泛型且resource函数的R默认值为null时,类型推断失效。原代码如下:
declare function resource<T, R = null>(options: ResourceOptions<T, R>): R; interface ResourceOptions<T, R> { params?: () => R; loader: (param: R) => T; } function xx<T>(source: T): () => T { return () => source; } const res = resource({ params: xx(""), loader: (params) => params, });
核心原因
原resource函数的泛型参数顺序是T在前、R在后。TypeScript会优先推断靠前的泛型参数,而T的推断依赖loader的参数类型(即R),但R有默认值null,导致TypeScript直接将R设为null,进而与params返回的string类型冲突,推断失败。
解决方案
方案1:调整泛型参数顺序(推荐)
将R放在T前面,让TypeScript先从params推断R的类型,再基于R推断T:
declare function resource<R = null, T>(options: ResourceOptions<T, R>): R; interface ResourceOptions<T, R> { params?: () => R; loader: (param: R) => T; } function xx<T>(source: T): () => T { return () => source; } const res = resource({ params: xx(""), loader: (params) => params, }); // res 的类型被正确推断为 string
方案2:显式指定部分泛型参数
如果不想调整泛型顺序,可以在调用resource时显式指定R的类型,让T自动推断:
const res = resource<string, string>({ params: xx(""), loader: (params) => params, });
方案3:优化接口类型关联
通过修改ResourceOptions,让loader的参数类型与params的返回值类型强关联,无需依赖泛型顺序:
declare function resource<T, R = null>(options: ResourceOptions<T, R>): R; interface ResourceOptions<T, R> { params?: () => R; loader: (param: NonNullable<R>) => T; } // 调用时通过类型断言辅助推断 const res = resource({ params: xx("") as () => string, loader: (params) => params, });
说明
方案1是最简洁自动的解决方式,完全利用TypeScript的泛型推断优先级规则,无需额外手动指定类型,同时保留了R=null的默认值。
内容的提问来源于stack exchange,提问作者Matthieu Riegler
相关产品推荐
相关产品推荐

