简体   繁体   English

Typescript 模板文字类型来自 object 数组

[英]Typescript template literal type from object array

const source = [
  { group: 'first', key: 'A' },
  { group: 'first', key: 'B' },
  { group: 'second', key: 'A' }
] as const;

type DerivedGroupKeys = `${typeof source[number]['group']}.${typeof source[number]['key']}`;
//gives "first.A" | "first.B" | "second.A" | "second.B"
type HardCodedGroupKeys = 'first.A' | 'first.B' | 'second.A';
//gives "first.A" | "first.B" | "second.A"

I would like the DerivedGroupKeys to be the same as HardCodedGroupKeys (without hardcoding).我希望DerivedGroupKeysHardCodedGroupKeys相同(没有硬编码)。 I am almost there but it is giving me every possible combination of group and key rather than just the combinations defined in the array.我快到了,但它为我提供了组和键的所有可能组合,而不仅仅是数组中定义的组合。 Is this possible?这可能吗?

The docs of Template Literal Types say that: Template Literal Types的文档说:

When a union is used in the interpolated position, the type is the set of every possible string literal that could be represented by each union member:当在插值 position 中使用联合时,类型是每个联合成员可以表示的每个可能的字符串文字的集合:

To overcome this issue, you can map each array element separately, instead of mapping the union.为了克服这个问题,您可以将 map 每个数组元素分开,而不是映射联合。

const source = [
  { group: 'first', key: 'A' },
  { group: 'first', key: 'B' },
  { group: 'second', key: 'A' }
] as const;

type ToLiteral<T> = 
  T extends {group: infer G, key: infer K} ? 
    G extends string ? 
      K extends string ? `${G}.${K}` : never 
    : never 
  : never;

type SourceElemsType = typeof source[number]
type SourceElesLiterals = ToLiteral<SourceElemsType>

This behavior is expected, to quote the handbook:这种行为是预期的, 引用手册:

For each interpolated position in the template literal, the unions are cross multiplied:对于模板文字中的每个插值 position,联合交叉相乘:

What you want is possible, but involves a couple of extra steps.你想要什么是可能的,但需要几个额外的步骤。 If you think about it, when you index a tuple with number , the resulting type can be any of the types of tuple members (hence, the union).如果你考虑一下,当你用number索引一个元组时,结果类型可以是任何类型的元组成员(因此,联合)。 What you need is to narrow the index type to a numeric literal : if you index a tuple with a literal N, the resulting type can only be the type of the Nth member of the tuple (hence, no union).您需要将索引类型缩小为数字文字:如果您使用文字 N 索引元组,则结果类型只能是元组的第 N 个成员的类型(因此,没有联合)。

First, we can get a union of the indices of the tuple:首先,我们可以得到元组索引的并集:

type Indices<A> = Exclude<keyof A, keyof any[]>;

Next, simply create a mapped type from tuple with "keys" as tuple indices and "values" as the desired output.接下来,只需从元组创建一个映射类型,其中“键”作为元组索引,“值”作为所需的 output。 Finally, just index the mapped type with tuple indices:最后,只需使用元组索引对映射类型进行索引:

type DerivedGroupKeys = { [ I in Indices<typeof source> ] : `${typeof source[I]['group']}.${typeof source[I]['key']}` }[Indices<typeof source>];

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

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