将数组映射到接口

时间:2018-07-14 00:50:00

标签: typescript typescript-typings typescript2.0 tsc

说我有一个看起来像这样的数组:

const options =  [
 {
   name: 'foo',
   type: 'boolean'
 },

 {
   name: 'bar',
   type: 'string'
 },

 {
   name: 'bar', // should be baz not bar
   type: 'number'
 }

]

我希望将此数组用作接口,如下所示:

export interface Opts {
   foo: boolean,
   bar: string,
   baz: number
}

所以可能必须是这样的:

export type Opts = manipulate(typeof options);

操纵是我希望发现的一些神奇的TS功能。

我认为这是一个不错的起点: https://blog.mariusschulz.com/2017/01/20/typescript-2-1-mapped-types

但是很难弄清楚。

1 个答案:

答案 0 :(得分:6)

是的,您可以执行此操作,但是它同时需要mappedconditional类型。

首先,您需要一个类型,该类型表示从"boolean"这样的类型名称到boolean这样的实际类型的映射。

type TypeMapping = {
  boolean: boolean,
  string: string,
  number: number,
  // any other types
}

然后,您需要一个帮助程序函数,以确保您的options值不会得到nametype属性扩展为string的类型。 (如果您检查options值,则其类型类似于{name: string, type: string}[],它失去了对所需的特定nametype值的跟踪。)可以使用{ {3}}为此,如下:

const asOptions = <K extends keyof any, 
  T extends Array<{ name: K, type: keyof TypeMapping }>>(t: T) => t;

让我们看看它是否有效:

const options = asOptions([
  {
    name: 'foo',
    type: 'boolean'
  },

  {
    name: 'bar',
    type: 'string'
  },

  {
    name: 'bar',
    type: 'number'
  }
]);

如果您检查一下,将发现它现在是一个数组类型,其中nametype中的每一个都缩小为文字"foo""bar",{ {1}},等等。

最后,我们必须执行所需的"number"类型的函数。我称它为manipulate

OptionsToType

这似乎很复杂。让我们看看是否可以分解它。

type OptionsToType<T extends Array<{ name: keyof any, type: keyof TypeMapping }>>
  = { [K in T[number]['name']]: TypeMapping[Extract<T[number], { name: K }>['type']] }

表示T extends Array<{ name: keyof any, type: keyof TypeMapping }> 必须是一个对象数组,其中包含一个T字段(例如对象键)和一个name字段(例如上面的type类型的键)。< / p>

TypeMapping

= { [K in T[number]['name']]: ... } 数组的每个元素中遍历name属性中的所有键名

T

表示“找到与名称 Extract<T[number], { name: K }> 相对应的T元素” ...

K

...并查找其 Extract<T[number], { name: K }>['type'] 属性...

'type'

...并将其用作 TypeMapping[Extract<T[number], { name: K }>['type']] 类型的索引。

好的,让我们看看它是否有效:

TypeMapping

如果您检查export type Opts = OptionsToType<typeof options>; ,则会看到:

Opts

正如您所期望的那样-等等,为什么{ foo: boolean; bar: string | number; } 类型的bar属性呢?哦,因为您将string | number放在bar中两次了。将第二个更改为options,这将是您期望的。

好的,希望能有所帮助。祝你好运!