使用 Typescript 枚举值创建新类型

a.g*_*g87 7 typescript

我有以下场景:

enum FieldsMap {
  User = "user-name",
  Password = "user-password",
  Country = "user-country"
}

type Fields = "user-name" | "user-password" | "user-country";
Run Code Online (Sandbox Code Playgroud)

你可以看到Fields正在重复的值FieldsMap,有没有一种方法Fields可以使用FieldsMap,以避免重复?另外,我使用的FieldsMap是一个enum在这里,但我可以改变,如果有必要,我只是想避免使用字符串尽可能:

const onChangeHandler = (key: Fields, value: string) => {
  switch (key) {
    case FieldsMap.User:
      // do something with `value`
      break;
    case FieldsMap.Password:
      // do something with `value`
      break;
    case FieldsMap.Country:
      // do something with `value`
      break;
  }
};
Run Code Online (Sandbox Code Playgroud)

jca*_*alz 12

TS4.1+ 更新:正如另一个答案所指出的,您现在可以使用模板文字类型来获取FieldsMap枚举值的字符串表示形式:

type Fields = `${FieldsMap}`;
// type Fields = "user-name" | "user-password" | "user-country"
Run Code Online (Sandbox Code Playgroud)

但重要的是要确保您确实需要它;enums的普通用例是您不希望对实际字符串文字值本身有太多依赖;对于名为 的枚举Foo,类型Foo已经是枚举值的联合,但它们被名义上对待,因此您不会意外地使用字符串代替它。如果您真的想使用字符串代替值,您可能一开始就不需要 an enum,而应该只使用其中包含字符串文字的对象。重点是:在使用之前确保这是您真正想要的。


只是将其写出来作为答案......在 TypeScript 中,枚举本质上已经具有您正在寻找的行为,而无需定义任何其他类型。

即,以下枚举定义:

enum Fields {
  User = "user-name",
  Password = "user-password",
  Country = "user-country"
}
Run Code Online (Sandbox Code Playgroud)

带来到范围命名Fields,与性质,其键UserPassword以及Country和其值"user-name""user-password""user-country"分别,你也知道。该值使其进入运行时,如下所示:

const x = Fields.User; // makes it to the emitted JS
Run Code Online (Sandbox Code Playgroud)

并且类似于以下值:

const FieldsLike = {
  User: "user-name",
  Password: "user-password",
  Country: "user-country"
} as const;

const xLike = FieldsLike.User; // makes it to the emitted JS;
Run Code Online (Sandbox Code Playgroud)

但它也带来了进入范围类型命名Fields,这相当于在工会中的属性值的Fields对象。当 JS 发出时,此类型会与类型系统的其余部分一起擦除,但可以在设计时通过类型注释和使用 IntelliSense 进行访问,如下所示:

const y: Fields = x; // the "Fields" annotation is the type
Run Code Online (Sandbox Code Playgroud)

并且类似于类型

type FieldsLike = (typeof FieldsLike)[keyof typeof FieldsLike];
// type FieldsLike = "user-name" | "user-password" | "user-country"

const yLike: FieldsLike = xLike; // the "FieldsLike" annotation is the type
Run Code Online (Sandbox Code Playgroud)

这是您正在寻找的类型;见下文。

顺便说一句,枚举充当命名空间,为每个枚举成员导出类型:

const z: Fields.Password = Fields.Password; // type and value
Run Code Online (Sandbox Code Playgroud)

(所以Fields.Password左边是类型的名称,而Fields.Password右边是的名称)。因此可访问的类型Fields类似于命名空间:

namespace FieldsLike {
  export type User = typeof FieldsLike.User;
  export type Password = typeof FieldsLike.Password;
  export type Country = typeof FieldsLike.Country;
}

const zLike: FieldsLike.Password = FieldsLike.Password; // type and value
Run Code Online (Sandbox Code Playgroud)

呼,只是用该方法enum Fields { ... }定义给我们的行为 const FieldsLike = ...type FieldsLike = ...以及namespace FieldsLike在一次所有。

让我们备份......你正在寻找的类型,Fields枚举下所有属性的联合,已经是一个名为Fields. (好吧,我改变了你的名字FieldsMapFields),你可以直接使用它:

const onChangeHandler = (key: Fields, value: string) => {
  switch (key) {
    case Fields.User:
      // do something with `value`
      break;
    case Fields.Password:
      // do something with `value`
      break;
    case Fields.Country:
      // do something with `value`
      break;
  }
};
Run Code Online (Sandbox Code Playgroud)

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

代码链接


PJC*_*der 6

模板文字类型发布后,您可以使用:

type Fields = `${FieldsMap}` // "user-name" | "user-password" | "user-country"
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的答案!节省了我很多时间。谢谢! (2认同)