简体   繁体   English

Typescript 泛型到 map 一个常量对象数组到一个类型列表

[英]Typescript Generic to map an array of const objects to a list of types

I have some JSON data that I've strongly typed with an as const assertion.我有一些 JSON 数据,我用as const断言强类型化了这些数据。

const myList = [
  { type: 'uint256'},
  { type: 'address'}
] as const;

Now I want to convert this to the following tuple type:现在我想将其转换为以下元组类型:

[number, string]

Basically, if the type is "address" it should resolve to string .基本上,如果类型是“地址”,它应该解析为string

If the type is a "uint256", it should resolve to number .如果类型是“uint256”,它应该解析为number

I intend to use this type to create arrays of data that conform to this schema, eg:我打算使用这种类型来创建 arrays 符合这种模式的数据,例如:

const foo: ConvertToTuple<typeof myList> = [1, 'asdf'];

I'm struggling to write a generic that can do this.我正在努力编写一个可以做到这一点的泛型。 Here's where I'm at so far:到目前为止,这是我所在的位置:

type ConvertToTuple<
  DataObjects extends readonly { type: "address" | "uint256" }[]
> = DataObjects extends readonly [infer CurrentObject, ...infer RestObjects]
  ? CurrentObject["type"] extends "address"
    ? [string, ...ConvertToTuple<RestObjects>]
    : CurrentObject["type"] extends "uint256"
    ? [number, ...ConvertToTuple<RestObject>]
    : never
  : [];

I don't think I'm using infer correctly here.我认为我在这里没有正确使用infer Typescript is throwing a couple of errors: Typescript 抛出几个错误:

Type '"type"' cannot be used to index type 'CurrentObject'

and

Type 'RestObjects' does not satisfy the constraint 'readonly { type: "address" | "uint256"; }[]'.
  Type 'unknown[]' is not assignable to type 'readonly { type: "address" | "uint256"; }[]'.
    Type 'unknown' is not assignable to type '{ type: "address" | "uint256"; }'.

Any help untangling this is much appreciated!非常感谢任何帮助解决这个问题的帮助!

TypeScript added extends constraints on infer type variables in version 4.7, so you can simplify the recursive mapped type utility like this: TypeScript 在版本 4.7 中添加了infer类型变量的extends约束,因此您可以像这样简化递归映射类型实用程序:

TS Playground TS游乐场

type ListType = "address" | "uint256";
type ListElement = { type: ListType };

type Transform<Tup extends readonly ListElement[]> =
  Tup extends readonly [
    infer H extends ListElement,
    ...infer R extends readonly ListElement[]
  ]
    ? [
      H["type"] extends "address" ? string : number,
      ...Transform<R>
    ]
    : Tup;

const myList = [
  { type: "uint256" },
  { type: "address" },
] as const satisfies readonly ListElement[];

type Foo = Transform<typeof myList>;
   //^? type Foo = [number, string]

const foo: Foo = [1, "asdf"]; // ok


If your enumeration of possible string literal types ends up growing, you can also use a type mapping of string literals to their corresponding types like this:如果您对可能的字符串文字类型的枚举最终增加,您还可以使用字符串文字到它们相应类型的类型映射,如下所示:

TS Playground TS游乐场

type TransformTypeMap = {
  address: string;
  uint256: number;
};

type Transform<Tup extends readonly ListElement[]> =
  Tup extends readonly [
    infer H extends ListElement,
    ...infer R extends readonly ListElement[]
  ]
    ? [TransformTypeMap[H["type"]], ...Transform<R>]
    : Tup;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM