【问题标题】:transform named tuple to object将命名元组转换为对象
【发布时间】:2021-10-26 03:00:23
【问题描述】:

有没有办法转换命名/标记元组

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

反对

type Obj = {
     a: string;
     b: number;
}

最后一次尝试无效

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,
};

谢谢

【问题讨论】:

  • @Andikac 这是不可能的。标签仅用于可读性/调试。可以将元组减少为对象表示,但输出将是{0:string, 1: number}。看到这个答案stackoverflow.com/questions/69299590/…
  • 鉴于[a: string, b: number] 和[c: string, d: number] 类型相同,没有原则性的方法可以将该单一类型转换为{a: string, b: number} 而不是{c: string, d: number}。这些标签并不是明显的类型的一部分。如果您愿意传入像RemapTupleKeys&lt;Tup, ["a", "b"]&gt; 这样的名称元组,那么有办法做到这一点(例如this code)。如果你想把它写成答案,请告诉我。
  • @captain-yossarian 我需要“重载”实现函数 FnParam(a: string, b: number) {} function FnDestructure({a, b} : TupleToObject> ) {},减少到 {0:string, 1: number} 不起作用
  • @jcalz 是的,请写下来作为答案,在等待 Roberto Zvjerković 评论中的此功能时,这是一个不错的选择

标签: typescript


【解决方案1】:

在microsoft/TypeScript#38234 中实现的TypeScript 对labeled tuple elements 的支持故意不提供任何方法来观察类型系统中的这些标签。从实施拉取请求:

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

另请参阅this comment 在相关问题中,TS 团队的开发负责人说:

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

从类型系统的角度来看,元组类型[a: string, b: number] 和元组类型[c: string, d: number] 是无法区分的。它们之间的唯一区别是它们如何在 IDE 中显示或作为文档输出。它们更像是 cmets 而不是代码。

如果[a: string, b: number] 和[c: string, d: number] 是同一类型,那么任何将[a: string, b: number] 转换为{a: string, b: number} 的类型函数TupleToObject&lt;T&gt; 也需要将[c: string, d: number] 转换为{a: string, b: number}。

所以真的没有希望实现你正在寻找的东西。元组标签故意对类型系统隐藏。元组标签和字符串literal types之间没有任何联系。


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

好的,那么有人将如何实现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] };

它有两个类型参数:T 是元组类型,而M 是一个至少相同长度的元组类型,其值为键。 extends readonly any[] 和 extends Record&lt;Exclude&lt;keyof T, keyof any[]&gt;, PropertyKey&gt;&gt; generic constraints 或多或少强制执行此操作。

然后,对于T 元组的每个字面数字键,我们使用key remapping 将该键替换为来自M 的相应条目。唯一奇怪的是,我们使用Exclude&lt;keyof T, keyof any[]&gt;,而不是迭代keyof T。元组类型是数组,将包含数组方法名称,如"map"。我们不想担心"map",所以the Exclude&lt;T, U&gt; utility type 让我们说“来自T 的所有那些不是通用数组键的键”。对于元组,这往往只留下"0"、"1" 等。


让我们测试一下:

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

type Obj = TupleToObject<Tup, ["a", "b"]>
/* type Obj = {
    a: string;
    b: number;
} */

看起来不错!

Playground link to code

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-19
    • 2017-06-20
    • 2023-03-29
    • 2014-11-28
    • 1970-01-01
    • 1970-01-01
    • 2013-01-14
    • 2017-07-14
    相关资源
    最近更新 更多