将命名元组转换为对象

And*_*kac 10 typescript

有什么方法可以转换命名/标记元组

type Tup = [a: string, b: number];
Run Code Online (Sandbox Code Playgroud)

反对

type Obj = {
     a: string;
     b: number;
}
Run Code Online (Sandbox Code Playgroud)

最后一次尝试不起作用

type Map1<Container extends unknown[]> = {
     [K in keyof Container]: Container[K];
};

type Map2<Container extends Record<PropertyKey, any>, Replace> = {
     [K in keyof Container]: Replace;
};

let c1 : Map1<Tup> = {
     'a' : 's',
     'b' : 1,
};

let c2 : Map2<Tup> = {
     'a' : 's',
     'b' : 1,
};
Run Code Online (Sandbox Code Playgroud)

谢谢

jca*_*alz 8

TypeScript 对microsoft/TypeScript#38234中实现的带标签元组元素的支持有意不提供任何方法来观察类型系统中的这些标签。从实施拉取请求:

名称不会以任何方式影响可分配性,仅用于文档和快速信息。

另请参阅相关问题中的此评论,其中 TS 团队的开发负责人表示:

[元组标签]纯粹用于显示目的(类似于函数类型中的参数名称)

从类型系统的角度来看,元组类型[a: string, b: number]和元组类型[c: string, d: number]没有区别的。它们之间的唯一区别在于它们在 IDE 中的显示方式或作为文档输出的方式。它们更像是注释而不是代码。

如果[a: string, b: number][c: string, d: number]是相同类型,则任何类型函数变成TupleToObject<T>也需要变成[a: string, b: number]{a: string, b: number}[c: string, d: number]{a: string, b: number}

因此,确实没有希望实现您正在寻找的东西。元组标签故意对类型系统隐藏。元组标签和字符串文字类型之间没有任何联系。


相反,唯一可能的方法是手动指定要用于输入元组的每个元素的字符串文字键。所以不可行的事情TupleToObject<[a: string, b: number]>就变成了类似的事情TupleToObject<[a: string, b: number], ["a", "b"]>。您可以看到它不再关心元组标签;TupleToObject<[foo: string, bar: number], ["a", "b"]>必然会产生相同的类型。

好的,那么有人会如何实施呢TupleToObject?这是一种可能的方法:

type TupleToObject<T extends readonly any[],
  M extends Record<Exclude<keyof T, keyof any[]>, PropertyKey>> =
  { [K in Exclude<keyof T, keyof any[]> as M[K]]: T[K] };
Run Code Online (Sandbox Code Playgroud)

它需要两个类型参数:T是一个元组类型,而M是一个至少具有相同长度的元组类型,其值是键。和通用约束或多或少强制执行此操作extends readonly any[]extends Record<Exclude<keyof T, keyof any[]>, PropertyKey>>

然后,对于元组中每个类似数字的键T,我们使用键重新映射来将该键替换为 中的相应条目M。唯一奇怪的一点是,keyof T我们没有使用迭代,而是使用Exclude<keyof T, keyof any[]>. 元组类型是数组,并且将包含数组方法名称,例如"map". 我们不想担心"map",因此实用程序类型Exclude<T, U>我们说“所有这些键T都不是通用数组键”。对于元组,这往往只留下"0","1"等。


让我们测试一下:

type Tup = [a: string, b: number];

type Obj = TupleToObject<Tup, ["a", "b"]>
/* type Obj = {
    a: string;
    b: number;
} */
Run Code Online (Sandbox Code Playgroud)

看起来不错!

Playground 代码链接