TypeScript中无法用path索引满足ApiPaths类型的对象问题
TypeScript API路径联合类型构建报错问题解答
问题描述
在TypeScript中定义了EthereumAddress、Chain、ApiMethods、ApiPaths等类型,同时声明了符合ApiPaths<ApiMethods>类型的apiPaths常量。想要构建Paths类型,该类型是API所有可能路径的联合类型:
- 若
apiPaths的项包含chain参数,路径格式为${path}/${chain} - 若不包含
chain参数,路径格式为${path}
但编写Paths类型时出现两个报错:
Type 'T[K]["path"]' is not assignable to type 'string | number | bigint | boolean | null | undefined'.ts(2322)Type '"path"' cannot be used to index type 'T[K]'
疑问:明明apiPaths的所有值都包含path参数,且符合ApiPaths<ApiMethods>类型,为什么path不被识别为T[K]的属性?
核心原因
TypeScript编译器在处理泛型索引时,需要明确的类型约束来确认目标属性存在于泛型的所有可能分支中。即便你知道apiPaths的每个成员都有path,但如果ApiPaths<T>的定义没有强制要求所有成员必须包含path字段,编译器无法自动推断这一点。
比如如果ApiPaths是类似下面的松散定义,编译器就无法确认T[K]一定包含path:
type ApiPaths<T> = { [K in keyof T]: { chain?: Chain; // 未强制声明path为必填属性 } };
解决方法
1. 强制ApiPaths成员包含path字段
修改ApiPaths的定义,将path设为必填属性,从根源上消除类型歧义:
type ApiPaths<T> = { [K in keyof T]: { path: string; // 明确为必填属性 chain?: Chain; // 其他业务属性 } };
2. 在Paths类型中添加类型守卫
如果无法修改ApiPaths的定义,可通过条件类型先确认T[K]包含path,再进行路径拼接:
type Paths<T extends ApiPaths<any>> = { [K in keyof T]: T[K] extends { path: string } ? T[K] extends { chain: infer C } ? `${T[K]['path']}/${C}` : T[K]['path'] : never; }[keyof T];
这里的T[K] extends { path: string }相当于给编译器一个明确的类型提示,确保path属性存在后再处理后续逻辑。
3. 用Extract提取合法类型分支
若能确定apiPaths的所有成员都包含path,也可以用Extract来筛选出包含path的类型分支,强化类型推断:
type Paths<T extends ApiPaths<any>> = { [K in keyof T]: Extract<T[K], { path: string }> extends { chain: infer C } ? `${Extract<T[K], { path: string }>['path']}/${C}` : Extract<T[K], { path: string }>['path'] }[keyof T];
内容的提问来源于stack exchange,提问作者Riccardo Perego
相关产品推荐
相关产品推荐

