Typescript:声明元组索引的类型?

Iva*_*son 3 typescript

给定一个 TypeScript 元组,例如:

const arr = [1, 2] as const;
Run Code Online (Sandbox Code Playgroud)

我们对索引进行静态类型检查:

console.log(arr[1]);
Run Code Online (Sandbox Code Playgroud)

很好,但是

console.log(arr[2]);
Run Code Online (Sandbox Code Playgroud)

错误:

长度为“2”的元组类型“readonly [1, 2]”在索引“2”处没有元素。ts (2493)

这太棒了。


我想声明一个常量为该元组索引的类型,以便分配给该常量的内容遵循相同的约束(0 | 1)。

我试过这个:

const index: keyof typeof arr = 2 as const;
console.log(arr[index]);
Run Code Online (Sandbox Code Playgroud)

但 TypeScript 没有显示任何错误。我怀疑这个index范围number太宽泛了。

jca*_*alz 7

是的,无论出于何种原因,元组索引都是数字字符串文字类型,例如"0"和 ,"1"而不是相应的数字文字类型,例如01。还有一个number 索引签名,所以keyof ["a", "b"]会给你number | "0" | "1" | ...。这意味着只需使用keyof即可让您分配任何数字。

如果要计算数字文字,可以使用模板文字类型来执行此操作,至少在 TypeScript 4.8 及更高版本中:

type TupleIndices<T extends readonly any[]> =
    Extract<keyof T, `${number}`> extends `${infer N extends number}` ? N : never;
Run Code Online (Sandbox Code Playgroud)

首先,我Extract通过过滤从完整键集中获取数字字符串文字类型`${number}`,即可以解析为数字的所有字符串的集合。这会消除number自身(不是字符串)以及"length"and"slice"和其他数组成员。这给了我们"0" | "1" | "2" | .... 然后,我使用TypeScript 4.8 中引入的改进infer类型将这些字符串文字转换为数字文字。

这给了你这个:

const arr = [1, 2] as const;

type ArrIndices = TupleIndices<typeof arr>;
// type ArrIndices = 0 | 1

type Also = TupleIndices<[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]>;
// type Also = 0 | 1 | 2 | 9 | 3 | 4 | 5 | 6 | 7 | 8
Run Code Online (Sandbox Code Playgroud)

Playground 代码链接