为什么TypeScript中无法从const数组推导出合法索引的字面量联合类型?
类型推导不符合预期的原因
TypeScript 对数组类型的keyof运算逻辑是遵循JavaScript数组的原生设计的:
- 数组本身带有
number类型的索引签名,允许任意数字作为下标访问,哪怕是const断言修饰的只读元组,也不会默认限制下标范围,这是为了兼容JS中常见的动态下标访问场景。 keyof 数组类型返回的结果除了number,还包含数组原型上的所有属性/方法名(比如length、push、map等),你示例中的number | keyof STATES就是这个逻辑的推导结果,并不会自动收拢为合法下标的字面量联合。
实现合法索引联合推导的方法
你可以通过自定义工具类型,利用TS 4.1及以上版本支持的模板字面量转数字特性,提取元组的合法下标联合:
const STATES = ["Todo", "In Progress", "Blocked", "Done"] as const; // 通用工具类型:提取只读元组的合法下标联合 type TupleIndices<T extends readonly any[]> = Exclude<keyof T, keyof any[]> extends `${infer N extends number}` ? N : never; type State = typeof STATES[number]; type StateIndex = TupleIndices<typeof STATES>; // 推导结果为 0 | 1 | 2 | 3 // 合法赋值通过校验 let goodIndex: StateIndex = 0; // 越界索引会报错 let badIndex : StateIndex = 42; // 错误:类型42不能分配给类型0 | 1 | 2 | 3
这个工具类型的逻辑是先把数组原型自带的属性名过滤掉,剩下的就是数字下标对应的字符串字面量(比如"0"、"1"),再把这些字符串转成数字字面量,就能得到你需要的合法索引联合。
内容的提问来源于stack exchange,提问作者andrewdotnich
相关产品推荐
相关产品推荐

