Typescript嵌套索引类型

时间:2019-07-18 19:19:51

标签: typescript

我正在尝试编写类型级别函数Foo,该函数将获取“二维”数组的第一个元素的类型。我写了以下

type Foo<A extends any[][]> = {
    [I in keyof A]: First<A[I]>
}

type First<A extends any[]> = A[0]

此代码无法编译并出现以下错误

Type 'A[I]' does not satisfy the constraint 'any[]'.
  Type 'A[keyof A]' is not assignable to type 'any[]'.
    Type 'A[string] | A[number] | A[symbol]' is not assignable to type 'any[]'.
      Type 'A[string]' is not assignable to type 'any[]'.

我正在努力理解。具体来说,A[string] | A[number] | A[symbol]的来源。据我了解,mapped arrays应该允许我索引应该是更多数组的数组元素。我可以通过定义First来解决条件类型的问题

type First<A> =
    A extends any[] ? A[0] :
    never;

但我不明白为什么这样做是必要的。

1 个答案:

答案 0 :(得分:2)

我知道这很令人讨厌。它被标记为bug。根本问题seems to be是编译器仅在您使用所映射的类型时才意识到它是在映射数组/元组,而不是在您定义时对其进行映射。

// here the compiler doesn't know that I will be a numeric-like key:
type Foo<A extends any[][]> = { [I in keyof A]: Extract<A[I], any[]>[0] };

// only here does the compiler perform the mapping with just the numeric-like keys:
type Expected = Foo<[[1, 2], [3, 4], [5, 6], [7, 8]]>;
// type Expected = [1, 3, 5, 7]

还可以使编译器将数组类型映射为纯对象,包括诸如lengthjoin等非数字键:

type Unexpected = Foo<[[1, 2], [3, 4], [5, 6], [7, 8]] & { a: string }>;
/* type Unexpected = {
    [x: number]: 1 | 3 | 5 | 7;
    0: 1;
    1: 3;
    2: 5;
    3: 7;
    length: never;
    toString: never;
    toLocaleString: never;
    pop: never;
    push: never;
    concat: never;
    join: never;
    reverse: never;
    shift: never;
    slice: never;
    sort: never;
    ... 18 more ...;
    a: never;
}
*/

这甚至是可能的事实意味着编译器无法假设A[I]可分配给any[],因此您目前不得不做类似Extract<A[I], any[]>的事情(类似于您的修复程序。)

希望有所帮助;祝你好运!

Link to code