将数组映射到接口 [英] Map array to an interface

查看:39
本文介绍了将数组映射到接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个如下所示的数组:

Say I have an array that looks like this:

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

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

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

]

我希望使用这个数组作为一个接口,它看起来像这样:

I am looking to use this array as an interface which would look something like this:

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

所以这可能必须是这样的:

so that would probably have to be something like:

export type Opts = manipulate(typeof options);

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

where manipulate is some magical TS feature I hope to discover.

我相信这是一个很好的起点:https://blog.mariusschulz.com/2017/01/20/typescript-2-1-mapped-types

I believe this is a good place to start: https://blog.mariusschulz.com/2017/01/20/typescript-2-1-mapped-types

但很难弄清楚.

推荐答案

是的,你可以这样做,但它需要 映射条件 类型.

Yes, you can do this, but it requires both mapped and conditional types.

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

First you need a type that represents your mapping from type names like "boolean", to actual types like boolean.

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

然后你需要一个辅助函数来确保你的 options 值不会得到它的 nametype 属性的类型扩展到<代码>字符串.(如果你检查你的 options 值,它的类型类似于 {name: string, type: string}[],它已经丢失了特定的 nametype 值.)您可以使用 通用约束来做到这一点,如下:

Then you need a helper function which makes sure your options value doesn't get its types for the name and type properties widened to string. (If you inspect your options value, its type is something like {name: string, type: string}[], which has lost track of the particular name and type values you want.) You can use generic constraints to do this, as follows:

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

让我们看看它是否有效:

Let's see if it works:

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

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

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

如果你检查你会发现它现在是一个类型数组,其中每个 nametype 都被缩小到文字 "foo""bar""number"

If you inspect that you will see that it is now an array of types where each of name and type are narrowed to the literals "foo", "bar", "number", etc.

最后我们必须做你想要的 manipulate 类型的函数.我称之为OptionsToType:

Finally we have to do that manipulate type function you want. I'll call it OptionsToType:

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

这可能看起来很复杂.看看能不能破解

That might seem very complicated. Let's see if I can break it down.

T extends Array<{ name: keyof any, type: keyof TypeMapping }>

表示 T 必须是一个对象数组,其中 name 字段像对象键一样,type 字段像对象键一样TypeMapping 在上面输入.

means T must be an array of objects with a name field like an object key, and a type field like a key of the TypeMapping type above.

  = { [K in T[number]['name']]: ... }

T 数组的每个元素遍历 name 属性中的所有键名

iterate through all the key names in the name property from each element of the T array

  Extract<T[number], { name: K }>

的意思是找到T中对应名称K的元素"...

means "find the element of T that corresponds to the name K"...

  Extract<T[number], { name: K }>['type']

...并查找它的 'type' 属性...

...and look up its 'type' property...

  TypeMapping[Extract<T[number], { name: K }>['type']]

...并将其用作 TypeMapping 类型的索引.

...and use that as an index into the TypeMapping type.

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

Okay let's see if it works:

export type Opts = OptionsToType<typeof options>;

如果你检查 Opts 你会看到:

And if you inspect Opts you see:

{
    foo: boolean;
    bar: string | number;
}

正如你所期望的---呃,等等,为什么 bar 属性的类型是 string |号码?哦,因为您将 bar 放在 options 中两次.将第二个更改为 baz,这将是您所期望的.

just as you expected--- uh, wait, why is the bar property of type string | number? Oh, because you put bar in options twice. Change the second one to baz and it will be what you expect.

好的,希望有帮助.祝你好运!

Okay, hope that helps. Good luck!

这篇关于将数组映射到接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆