TypeScript数组类型进阶问题:自定义索引取类型及相关疑问
问题解答
1. 实现索引超出数组长度时返回never类型
要实现该需求,需要在类型层面判断索引N是否处于数组的有效范围(0 ≤ N < T['length'])。可以通过递归生成有效索引范围,再判断N是否属于该范围来实现:
// 生成从0到N-1的数字字面量联合类型 type NumberLessThan<N extends number, Acc extends number[] = []> = Acc['length'] extends N ? Acc[number] : NumberLessThan<N, [...Acc, Acc['length']]>; // 改进后的El类型 type El<T extends unknown[], N extends number> = N extends NumberLessThan<T['length']> ? T[N] : never; // 测试用例 type Test1 = El<[1, '2', 4], 2>; // 4(有效索引) type Test2 = El<[1, '2', 4], 3>; // never(超出长度) type Test3 = El<[], 0>; // never(空数组)
也可以用更简洁的方式,利用TypeScript元组索引的特性——仅当N是元组的有效元素索引时,T[N]才返回对应类型,否则通过条件判断返回never:
type El<T extends unknown[], N extends number> = T extends { [K in N]: infer U } ? U : never; type Test4 = El<[1, '2', 4], 3>; // never
2. 为什么el2的类型是string | number而非number?
你定义的const arr = [1,'2',4]被TypeScript默认推断为数组类型(string | number)[],而非元组类型[1, '2', 4]。数组类型的所有元素都是联合类型,因此无论索引是多少,T[N]都会返回元素的联合类型string | number。
若要让TypeScript将其推断为元组,需要使用as const断言,强制保留字面量类型和元组结构:
const arr = [1,'2',4] as const; // 类型为readonly [1, "2", 4] let el2: El<typeof arr, 2>; // 类型为4,符合预期
3. 为什么el3会报错?
类型参数T要求传入的是类型,而arr是一个值,并非类型。在TypeScript中,要获取值的类型必须使用typeof操作符,因此正确写法是El<typeof arr, 2>,而非直接传递arr作为类型参数。
内容的提问来源于stack exchange,提问作者alexandr2006
相关产品推荐
相关产品推荐

