如何用TypeScript泛型将const对象数组映射为类型元组?
解决TypeScript中基于const断言数组转换元组类型的泛型问题
需求场景
通过as const断言给JSON结构数组添加强类型:
const myList = [ { type: 'uint256'}, { type: 'address'} ] as const;
需要将其转换为对应元组类型[number, string],转换规则:
- 当元素的
type为"address"时,对应元组位置类型为string - 当元素的
type为"uint256"时,对应元组位置类型为number
最终要实现如下类型约束:
const foo: ConvertToTuple<typeof myList> = [1, 'asdf'];
原代码的问题
原泛型实现存在两处关键问题:
type ConvertToTuple< DataObjects extends readonly { type: "address" | "uint256" }[] > = DataObjects extends readonly [infer CurrentObject, ...infer RestObjects] ? CurrentObject["type"] extends "address" ? [string, ...ConvertToTuple<RestObjects>] : CurrentObject["type"] extends "uint256" ? [number, ...ConvertToTuple<RestObject>] // 拼写错误:RestObject应为RestObjects : never : [];
抛出的错误原因:
Type '"type"' cannot be used to index type 'CurrentObject':infer CurrentObject时未添加类型约束,TypeScript无法确定该类型存在type属性Type 'RestObjects' does not satisfy the constraint...:infer RestObjects同样无类型约束,TS默认推断为unknown[],不满足泛型参数的数组约束
修正后的泛型实现
我们需要在infer阶段为推断的类型添加明确约束,同时优化类型映射逻辑:
// 定义类型映射表,让转换规则更直观 type TypeMap = { uint256: number; address: string; }; type ConvertToTuple<T extends readonly { type: keyof TypeMap }[]> = T extends readonly [ infer Head extends { type: keyof TypeMap }, ...infer Tail extends readonly { type: keyof TypeMap }[] ] ? [TypeMap[Head['type']], ...ConvertToTuple<Tail>] : [];
验证效果
使用修正后的泛型,可正确完成类型转换:
const myList = [ { type: 'uint256'}, { type: 'address'} ] as const; // 类型被正确推断为 [number, string] const foo: ConvertToTuple<typeof myList> = [1, 'asdf']; // 类型不匹配时会触发TS报错(符合预期) // const bar: ConvertToTuple<typeof myList> = ['1', 'asdf'];
关键优化点
- 抽离类型映射表:把
type字符串与目标类型的对应关系单独定义为TypeMap,后续扩展新类型时只需修改该映射表 - 给infer添加约束:在推断元组头部和剩余元素时,明确约束它们的结构类型,解决索引访问和泛型约束不满足的问题
- 递归拼接元组:通过递归逻辑逐个处理元组元素,将每个元素的
type映射为目标类型,最终拼接成符合要求的元组类型
内容的提问来源于stack exchange,提问作者Danny Delott
相关产品推荐
相关产品推荐

