我即将解决这个问题,但找不到解决最后TS2322: Type  TcolTuple[i]  is not assignable to type  string | number | symbol个编译器错误的方法.

所以,这是一个实用函数rowsToObjects(),相当多的人可能在他们的项目中定义了一两次,它在概念上有点类似于zip():

const objects = rowsToObjects(
    ['id', 'color' , 'shape'   , 'size'  , 'to' ] as const,  
    [  1n, 'red'   , 'circle'  , 'big'   , '0x0'] as const,
    [  2n, 'green' , 'square'  , 'small' , '0x0'] as const,
    [  3n, 'blue'  , 'triangle', 'small' , '0x0'] as const,
)

这会产生以下结果:

[
    {id: 1n, color: 'red', shape: 'circle', size: 'big', to: '0x0'},
    {id: 2n, color: 'green', shape: 'square', size: 'small', to: '0x0'},
    {id: 3n, color: 'blue', shape: 'triangle', size: 'small', to: '0x0'},
]

实际的实现显然是微不足道的,但输入它会让我感到很困难:

export function rowsToObjects<
    Tobj extends { [i in keyof TcolTuple as TcolTuple[i]]: TvalTuple[i] },
    TcolTuple extends readonly string[],
    TvalTuple extends { [j in keyof TcolTuple]: unknown }
>(cols: TcolTuple, ...rows: TvalTuple[]): Tobj[];

当前代码对我来说似乎是合乎逻辑的,但编译器抱怨as TcolTuple[i]部分:

TS2322: Type  TcolTuple[i]  is not assignable to type  string | number | symbol 
  Type  TcolTuple[keyof TcolTuple]  is not assignable to type  string | number | symbol 
    Type
    TcolTuple[string] | TcolTuple[number] | TcolTuple[symbol]
    is not assignable to type  string | number | symbol 
      Type  TcolTuple[string]  is not assignable to type  string | number | symbol 

我是不是漏掉了什么明显的东西?输入接近令人满意,但如果没有这as TcolTuple[i],它就无法识别哪个值属于哪个键,而只是将它们全部合并.

enter image description here

推荐答案

我认为你遇到的主要问题是

{ [I in keyof TcolTuple as TcolTuple[I]]: TvalTuple[I] }

使用key remapping可以防止映射的类型为homomorphic(请参见What does "homomorphic mapped type" mean?),因此不是像"0" | "1" | "2"那样映射mapping over just the numeric-like indices of the tuple,而是映射all个以上的索引,包括number,所有元素的混合.这就给了你你不满意的union.

这里最简单的改变是只显式地映射类似数字的索引,通过intersecting keyof TcolTuplepattern template literal type `${number}`(如microsoft/TypeScript#40598中所实现的).它删除任何不是数字的字符串版本的内容. 例如,"0" | "1" | "2" | number | "length" | "find"`${number}`相乘,得到的结果是"0" | "1" | "2".

这或多或少解决了这个问题:

declare function rowsToObjects<
  Tobj extends { [I in `${number}` & keyof TcolTuple as TcolTuple[I]]: TvalTuple[I] },
  TcolTuple extends readonly string[],
  TvalTuple extends { [J in keyof TcolTuple]: unknown }
>(cols: TcolTuple, ...rows: TvalTuple[]): Tobj[];

const objects = rowsToObjects(
  ['id', 'color', 'shape', 'size', 'to'] as const,
  [1n, 'red', 'circle', 'big', '0x0'] as const,
  [2n, 'green', 'square', 'small', '0x0'] as const,
  [3n, 'blue', 'triangle', 'small', '0x0'] as const,
)
/* const objects: {
    id: 1n | 2n | 3n;
    color: "red" | "green" | "blue";
    shape: "circle" | "square" | "triangle";
    size: "big" | "small";
    to: "0x0";
}[] */

就我个人而言,如果我为自己写这篇文章,我会:

  • 使用const type parameters而不是要求呼叫者使用const assertions
  • 维护输入的元组类型,以便如果输入数组是强有序的,那么输出也是强有序的(例如,rowsToObjects(["a"],[0],[1])应该返回[{a: 0}, {a: 1}],而不是{a: 0 | 1}[]
  • go 掉多余的generic个类型参数,只计算内联输出,而不是依赖default type arguments
  • 映射的类型参数使用大写字母,如IJ,而不是ij,遵循命名约定以区分类型和变量(在{[P in K]: F<P>}中,P是类型参数,而不是变量名,因此p可能会混淆).

所有这些都不是至关重要的,但它给了我们

declare function rowsToObjects<
  const K extends readonly PropertyKey[],
  const V extends readonly Record<keyof K, unknown>[]
>(
  cols: K, ...rows: V
): { [I in keyof V]:
    { [J in `${number}` & keyof K as K[J]]:
      V[I][J]
    }
  };

const objects = rowsToObjects(
  ['id', 'color', 'shape', 'size', 'to'],
  [1n, 'red', 'circle', 'big', '0x0'],
  [2n, 'green', 'square', 'small', '0x0'],
  [3n, 'blue', 'triangle', 'small', '0x0'],
)
/* const objects: readonly [{
    id: 1n;
    color: "red";
    shape: "circle";
    size: "big";
    to: "0x0";
}, {
    id: 2n;
    color: "green";
    shape: "square";
    size: "small";
    to: "0x0";
}, {
    id: 3n;
    color: "blue";
    shape: "triangle";
    size: "small";
    to: "0x0";
}] */

Playground link to code

Typescript相关问答推荐

Angular -使用Phone Directive将值粘贴到控件以格式化值时验证器不工作

TypScript ' NoInfer '类型未按预期工作

参数类型undefined不能分配给参数类型字符串|未定义

React router 6.22.3不只是在生产模式下显示,为什么?

我用相同的Redux—Toolkit查询同时呈现两个不同的组件,但使用不同的参数

Webpack说你可能需要在Reactjs项目中增加一个加载器''

在键和值为ARGS的泛型函数中未正确推断类型

如何通过TypeScript中的工厂函数将区分的联合映射到具体的类型(如类)?

Angular 错误NG0303在Angular 项目中使用app.Component.html中的NGFor

如何使用泛型自动推断TS中的类型

如何在TypeScrip中从字符串联合类型中省略%1值

STypescript 件的标引签名与功能签名的区别

嵌套对象的类型

确保对象列表在编译时在类型脚本中具有唯一键

顶点堆叠的图表条形图未在正确的x轴上显示

有没有办法在Reaction组件中动态导入打字脚本`type`?

使用&reaction测试库&如何使用提供程序包装我的所有测试组件

来自枚举的<;复选框和组件列表

我如何键入它,以便具有字符串或数字构造函数的数组可以作为字符串或数字键入s或n

Typescript 是否可以区分泛型参数 void?