TypeScript:约束传入函数的泛型类型参数问题
核心原因
TypeScript的泛型推断逻辑会主动尝试匹配满足约束的Params类型,而非严格校验传入的Fetcher泛型参数是否完全符合约束。具体来说:
- 你的
searchFetcher中fetch方法未声明接收params参数,根据TS函数兼容性规则,不接收参数的函数可以兼容接收任意参数的函数(调用时传入的参数会被忽略)。 - TS会自动推断
Params为SearchParams & PaginationParams,而由于fetch方法的参数兼容,Fetcher<SearchParams, ...>会被认为可赋值给Fetcher<SearchParams & PaginationParams, ...>,导致约束检查失效。
可行解决方案
方案1:明确约束fetch方法的参数类型
修改searchFetcher的fetch方法,明确声明参数类型,让TS无法进行宽松的兼容性推断:
const searchFetcher: Fetcher<SearchParams, SomeItemsResp> = { fetch: function(params: SearchParams): SomeItemsResp { // 显式标注参数类型 throw new Error("Function not implemented."); } }
此时调用paginateWithSearch(searchFetcher)会触发预期错误:TS会检测到SearchParams缺少PaginationParams的属性(如page/size),无法兼容联合约束类型。
方案2:直接限定函数参数的Fetcher类型
放弃函数泛型推断,直接定义合法的Fetcher类型并作为参数约束:
// 先定义合法的Fetcher类型 type ValidPaginatedSearchFetcher = Fetcher<PaginationParams & SearchParams, SomeItemsResp>; // 函数直接接收该类型参数 function paginateWithSearch(fetcher: ValidPaginatedSearchFetcher) { // 执行逻辑 }
这种方式从根源上限制了传入的Fetcher必须使用符合约束的泛型参数,不存在推断宽松的问题。
方案3:在函数内部添加强制类型检查
通过内部类型断言触发编译时检查,确保Params符合约束:
function paginateWithSearch<Params extends PaginationParams & SearchParams, Resp extends SomeItemsResp>(fetcher: Fetcher<Params, Resp>) { // 强制校验Params是否满足约束,不满足则编译报错 const _validateParams: Params = {} as PaginationParams & SearchParams; // 执行逻辑 }
验证示例
假设基础类型定义如下:
type PaginationParams = { page: number; size: number; }; type SomeItemsResp = { items: any[] };
使用方案1修改后,调用paginateWithSearch(searchFetcher)会得到预期错误:
Type 'Fetcher<SearchParams, SomeItemsResp>' is not assignable to type 'Fetcher<PaginationParams & SearchParams, SomeItemsResp>'.
Type 'SearchParams' is not assignable to type 'PaginationParams & SearchParams'.
Property 'page' is missing in type 'SearchParams' but required in type 'PaginationParams'.
内容的提问来源于stack exchange,提问作者Vadim

