【问题标题】:Map array to an interface将数组映射到接口
【发布时间】:2018-12-22 09:04:20
【问题描述】:

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

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

但很难弄清楚。

【问题讨论】:

    标签: typescript typescript-typings typescript2.0 tsc


    【解决方案1】:

    是的,你可以这样做,但它需要mappedconditional 类型。

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

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

    然后您需要一个辅助函数来确保您的options 值不会将nametype 属性的类型扩展到string。 (如果您检查您的options 值,它的类型类似于{name: string, type: string}[],它已经丢失了您想要的特定nametype 值。)您可以使用generic constraints 来执行此操作,如下所示:

    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""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 字段类似于上述TypeMapping 类型的键。

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

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

      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 两次。将第二个更改为baz,这将是您所期望的。

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

    【讨论】:

    猜你喜欢
    • 2021-12-25
    • 1970-01-01
    • 2019-01-06
    • 2019-04-07
    • 2020-11-29
    • 2017-11-26
    • 2022-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多