TypeScript报错:值可能为undefined但类型未声明为undefined
TypeScript中Payload类型为何会出现undefined的类型推断问题?
代码示例
type ApiMethods = { getToken(args: { tokenAddress: string; tokenName: string }): string; getRank(): string; getName(): string; }; type Payload<K extends keyof ApiMethods> = Parameters< ApiMethods[K] >[0] extends undefined ? {} : Parameters<ApiMethods[K]>[0]; function buildUrl<M extends keyof ApiMethods>( payload: Payload<M>, ) { let keys = Object.keys(payload) }
报错信息
No overload matches this call.
Overload 1 of 2, '(o: {}): string[]', gave the following error.
Argument of type '{} | { tokenAddress:0x${string}; tokenName: string; } | undefined' is not assignable to parameter of type '{}'.
问题分析
你疑惑的是,明明已经在Payload类型中设置:当函数的第一个参数类型是undefined时返回空对象{},但TypeScript仍推断payload可能为undefined。
问题出在TypeScript对无参数函数的Parameters工具类型处理,以及泛型条件类型的推断逻辑:
- 对于
getRank、getName这类无参数函数,Parameters<ApiMethods[K]>返回的是空元组[],而非包含undefined的元组。此时Parameters<ApiMethods[K]>[0]的类型是never,而非undefined。 - 虽然
never extends undefined的结果为true,理论上Payload<K>应返回{},但在泛型函数buildUrl中,TypeScript无法准确解析这个条件类型的结果,错误地将undefined纳入了payload的联合类型。
解决方案
调整Payload类型的判断逻辑,直接检查函数参数元组是否为空,而非依赖Parameters[0] extends undefined:
type ApiMethods = { getToken(args: { tokenAddress: string; tokenName: string }): string; getRank(): string; getName(): string; }; // 修改后的Payload类型:直接判断参数元组是否为空 type Payload<K extends keyof ApiMethods> = Parameters<ApiMethods[K]> extends [] ? {} : Parameters<ApiMethods[K]>[0]; function buildUrl<M extends keyof ApiMethods>( payload: Payload<M>, ) { let keys = Object.keys(payload) // 不再报错 }
这种方式能准确识别无参数函数的场景,将Payload<'getRank'>和Payload<'getName'>正确推断为{},payload的类型会被收窄为{} | { tokenAddress: string; tokenName: string },不再包含undefined,Object.keys调用自然正常。
内容的提问来源于stack exchange,提问作者Riccardo Perego
相关产品推荐
相关产品推荐

