如何将数组所有可能索引转为数字联合类型?
数组索引转数字联合类型问题解决
问题说明
需要将数组的所有可能索引转换为数字联合类型,但当前实现得到的是字符串联合类型,不符合预期:
期望结果
type VoiceSettings = { similarityLevel: 0 | 1 | 2 | 3 | 4 | 5; stabilityLevel: 0 | 1 | 2 | 3 | 4; }
实际结果
type VoiceSettings = { similarityLevel: "0" | "1" | "2" | "3" | "4"; stabilityLevel: "0" | "1" | "2" | "3" | "4"; }
现有代码
const VALUES_MAP = { similarityLevel: [0, 15, 30, 50, 75, 90], stabilityLevel: [15, 30, 60, 75, 90], } as const; type ValuesTypes = keyof typeof VALUES_MAP; type VoiceSettings = { [key in ValuesTypes]: Exclude<keyof (typeof VALUES_MAP)[ValuesTypes], keyof []>; };
解决方案
问题根源在于keyof获取数组索引时返回的是字符串类型(如"0"、"1"),以下两种方案可将其转换为数字联合类型:
方案一:字符串索引转数字类型
通过模板字面量工具类型将字符串形式的索引转换为数字:
const VALUES_MAP = { similarityLevel: [0, 15, 30, 50, 75, 90], stabilityLevel: [15, 30, 60, 75, 90], } as const; type ValuesTypes = keyof typeof VALUES_MAP; // 工具类型:将字符串索引转为对应数字 type StringToNumber<T extends string> = T extends `${infer N extends number}` ? N : never; type VoiceSettings = { [key in ValuesTypes]: StringToNumber<Exclude<keyof (typeof VALUES_MAP)[key], keyof []>>; };
方案二:基于数组长度生成数字范围
直接递归生成从0到数组长度-1的数字联合类型,逻辑更直观:
const VALUES_MAP = { similarityLevel: [0, 15, 30, 50, 75, 90], stabilityLevel: [15, 30, 60, 75, 90], } as const; type ValuesTypes = keyof typeof VALUES_MAP; // 递归生成0到N-1的数字范围类型 type NumberRange<N extends number, Acc extends number[] = []> = Acc['length'] extends N ? Acc[number] : NumberRange<N, [...Acc, Acc['length']]>; type VoiceSettings = { [key in ValuesTypes]: NumberRange<(typeof VALUES_MAP)[key]['length']>; };
说明
- 方案一针对已有的字符串索引做类型转换,适配场景更灵活;
- 方案二直接基于数组长度生成索引范围,代码更简洁,适合仅需数组合法索引的场景。
内容的提问来源于stack exchange,提问作者qweezz
相关产品推荐
相关产品推荐

