Typescript 2D可变参数模板

问题描述

我目前有一个使用其他接口类型数组的数据成员的接口,该接口可以由枚举确定:

enum E { a,b,c }
interface E2Data {
    [E.a]: { a: string },[E.b]: { b: string },[E.c]: { c: string }
}

interface A<T extends E[] = E[]> {
    data: { [i in keyof T]: T[i] extends E ? E2Data[T[i]] : never }
}

// Can give the enums in the template,and get autocomplete in the data.
let a1: A<[E.a,E.b]> = {
    data: [{ a: "" },{ b: "" }]
};

// Or can get autocomplete with type assertion on elements.
// Ideally this would infer template types too,but apparently not.
let a2: A = {
    data: [ <E2Data[E.a]>{ a: "" },<E2Data[E.b]>{ b: "" } ]
}

根据我的理解,我现在可以将a1.dataa2.data用作数组,但是a1.data知道每个元素的类型(实际上是元组吗?)

现在,我想对interface A的数据使用2D数组。

我认为下面的方法可以工作,但是不允许我使用E2DataT[i][j]编制索引。

interface B<T extends E[][] = E[][]> {
    data: {
        [i in keyof T]:
        T[i] extends E[] ? {
            [j in keyof T[i]]:
            T[i][j] extends E ? E2Data[T[i][j]] : never }
        //                      ^^^^^^^^^^^^^^^
        // Type 'T[i][j]' cannot be used to index type 'E2Data'.
        : never
    }
}

我当前的解决方法是使用类型联合,但这不能让我使用模板指定想要的数据。

interface B {
    data: (E2Data[E.a] | E2Data[E.b] | E2Data[E.c])[][];
}

对于2D数组,是否有一种方法可以支持data上的两种自动完成方法

let b1: A<[ [E.a],[E.b] ]> = {
    data: [ [{ a: "" }],[{ b: "" }] ]
}

let b2: A = {
    data: [ [<E2Data[E.a]>{ a: "" }],[ <E2Data[E.b]>{ b: "" }] ]
}

解决方法

这使我产生了一些思考,但是解决方案实际上非常简单,因为您已经用原始的interface A完成了大部分工作。

定义泛型类型DataArray,该泛型类型将E值的元组作为其泛型,并返回相应E2Data的元组。您可以重新设置格式,以使DataArray包含逻辑并A使用它,但为简单起见,我们仅从A访问现有逻辑。

type DataArray<T extends E[]> = A<T>['data'];

您可以使用单个索引签名并调用interface B类型来创建内部数组,而不是在DataArray中使用嵌套的索引签名。

interface B<T extends E[][] = E[][]> {
    data: {
        [i in keyof T]: T[i] extends E[] ? DataArray<T[i]> : never
    }
}

现在,您可以通过混合和匹配E来创建任何2D数据类型。

let b: B<[[E.a],[E.b,E.c]]> = {
    data: [ [{ a: "" }],[{ b: "" },{c: ""}] ]
}

修改 我知道您并没有要求这样做,但是这是处理更深层嵌套值的方法。 (在this answer中有一些有关递归数组的指导)。

interface Nested<T> extends Array<Nested<T> | T> {
}

type NestedData<T extends Nested<E>> = { 
    [i in keyof T]: T[i] extends E ? E2Data[T[i]] : T[i] extends Nested<E> ? NestedData<T[i]> : never
}

interface C<T extends Nested<E>> {
    data: NestedData<T>
}

let c: C<[E.a,[E.c]]]> = {
    data: [ { a: "" },[{c: ""}] ]]
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...