【问题标题】:How to build a type from enum values in TypeScript?如何从 TypeScript 中的枚举值构建类型?
【发布时间】:2019-08-04 03:31:51
【问题描述】:

鉴于以下情况:

enum FooKeys {
  FOO = 'foo',
  BAR = 'bar',
}

我想制作一个像这样的界面,但不是手动定义键,而是根据枚举的值构建它。

interface Foo {
  foo: string
  bar: string
}

TypeScript 可以做到这样的事情吗?

谢谢!

【问题讨论】:

    标签: typescript types typescript-generics


    【解决方案1】:

    是的,您可以使用枚举值作为键。你可以使用mapped type 像标准库的Record<K, V> 来防止重复:

    enum FooKeys {
      FOO = 'foo',
      BAR = 'bar',
    }
    
    // probably all you need, but it's a type alias
    type FooType = Record<FooKeys, string>;
    
    // if you need an interface instead you can do this
    interface FooInterface extends FooType {};
    

    您可以验证它是否有效:

    declare const foo: FooInterface;
    foo.foo; // okay
    foo[FooKeys.FOO]; // okay
    
    foo.bar; // okay
    foo[FooKeys.BAR]; // okay
    
    foo.baz; // error
    

    这对你有用吗?祝你好运!

    【讨论】:

    • 感谢您的详细解答。这正是我所需要的!
    • Record 中的Record&lt;FooKeys, string&gt; 是什么?为什么您决定在您的应用程序/代码/模块中添加另一种任意类型?为什么需要额外的类型?
    • 这是一个utility type,标准库中的定义在上面的答案中链接。
    【解决方案2】:

    @hackape 's solution 很棒,但我发现扩展他的解决方案的重复最少,如下所示:

    type ReverseMap<T extends Record<keyof T, any>> = {
      [V in T[keyof T]]: {
        [K in keyof T]: T[K] extends V ? K : never;
      }[keyof T];
    }
    
    const Map = {
      'FOO': "foo" as "foo",
      'BAR': "bar" as "bar",
    }
    
    const reverseMap: ReverseMap<typeof Map> = Object.entries(Map).reduce((rMap, [k, v]) => {
      rMap[v] = k;
      return rMap;
    }, {} as any);
    
    export type Values = keyof typeof reverseMap; // 'foo' | 'bar';
    

    ReverseMap 实现很好解释here

    【讨论】:

      【解决方案3】:

      这能回答你的问题吗?

      enum FOO_BAR {
          F = "foo",
          B = "bar",
      }
      
      type FooType = Record<FOO_BAR, string>;
      
      const obj: FooType = {
          // you can use enum values, better for refactoring
          [FOO_BAR.F]: "action foo",
          [FOO_BAR.B]: "action bar",
      
          // or use enum values
          // foo: "action foo",
          // bar: "action bar",
      };
      
      obj[FOO_BAR.F]; // -> "action foo"
      obj["foo"];     // -> "action foo"
      
      // If you want partial keys
      type FooTypePartial = Partial<FooType>;
      
      const objPartial: FooTypePartial = {
          [FOO_BAR.F]: "action foo",
      };
      
      objPartial["foo"]; // -> "action foo", may be undefined
      
      

      【讨论】:

        猜你喜欢
        • 2018-10-18
        • 2012-09-23
        • 1970-01-01
        • 2022-09-23
        • 2022-01-15
        • 1970-01-01
        • 1970-01-01
        • 2022-08-02
        相关资源
        最近更新 更多