为何TypeScript中call方法的返回类型被推断为never?
TypeScript无法正确推断call函数的返回类型问题
调用自定义的call函数时,参数类型能被正确校验(比如传入字符串会报错,因为该参数要求是数字),但返回值类型却被推断为never,导致无法正常访问res.results属性。
原代码
import { Client } from '@hubspot/api-client'; type GetReturnType<T> = T extends (...args: unknown[]) => Promise<infer U> ? U : never; type GetParameters<T> = T extends (...args: infer U) => unknown ? U : never; async function call<T extends 'crm', U extends keyof Client[T], V extends keyof Client[T][U], W extends keyof Client[T][U][V]>( method: [api: T, entity: U, apiSection: V, method: W], ...args: GetParameters<Client[T][U][V][W]> ): Promise<GetReturnType<Client[T][U][V][W]>> { [method, args] return undefined as any } const res = await call( ['crm', 'companies', 'basicApi', 'getPage'], 'test', // 此处正确报错:应为数字类型 undefined, ['city'], ); res.results; // res被推断为never,无法访问results
问题原因
原写法通过多层泛型约束(T extends 'crm'、U extends keyof Client[T]等)来限定路径,但TypeScript在处理这种多层嵌套的泛型关联时,无法准确追踪到最终的Client[T][U][V][W]对应的方法类型,导致GetReturnType无法提取出Promise包裹的实际返回值,最终返回never。
解决方案
调整泛型定义方式,让TypeScript基于传入的具体路径直接推断对应的方法类型,而非逐层约束键名:
import { Client } from '@hubspot/api-client'; type GetReturnType<T> = T extends (...args: unknown[]) => Promise<infer U> ? U : never; type GetParameters<T> = T extends (...args: infer U) => unknown ? U : never; async function call<Path extends [keyof Client, keyof Client[Path[0]], keyof Client[Path[0]][Path[1]], keyof Client[Path[0]][Path[1]][Path[2]]]>( method: Path, ...args: GetParameters<Client[Path[0]][Path[1]][Path[2]][Path[3]]> ): Promise<GetReturnType<Client[Path[0]][Path[1]][Path[2]][Path[3]]>> { [method, args] return undefined as any; } const res = await call( ['crm', 'companies', 'basicApi', 'getPage'], 1, // 传入符合要求的数字类型 undefined, ['city'], ); res.results; // 现在能正确推断类型,可正常访问results
简化思路说明
通过将路径定义为泛型Path,并直接用Path[0]、Path[1]等索引访问Client的嵌套类型,让TypeScript能基于传入的具体路径值,准确解析出目标方法的类型,进而正确提取参数和返回值类型。
内容的提问来源于stack exchange,提问作者Bart van den Burg
相关产品推荐
相关产品推荐

