简体   繁体   English

使用 Typescript 枚举值创建新类型

[英]Use Typescript enum values to create new type

I have the following scenario:我有以下场景:

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

type Fields = "user-name" | "user-password" | "user-country";

as you can see Fields is repeating the values of FieldsMap , is there a way that Fields can use the values of FieldsMap in order to avoid repetition?.正如您所看到的Fields正在重复FieldsMap的值,是否有一种方法可以让Fields使用FieldsMap来避免重复? Also, I'm using FieldsMap as an enum here, but I can change that if necessary, I'm just trying to avoid using strings as much as possible:另外,我在这里使用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;
  }
};

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

type Fields = `${FieldsMap}` // "user-name" | "user-password" | "user-country"

Just writing this out as an answer... in TypeScript, enums essentially already have the behavior you're looking for without needing to define any additional types. 只需将其写为答案...在TypeScript中, 枚举实际上已经具有您要寻找的行为,而无需定义任何其他类型。

That is, the following enum definition: 即,以下枚举定义:

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

brings into scope a value named Fields , with properties whose keys are User , Password , and Country , and whose values are "user-name" , "user-password" , and "user-country" , respectively, as you know. 如您所知,将名为Fields纳入范围,其属性的键分别为UserPasswordCountry ,其值分别为"user-name""user-password""user-country" This value makes it to runtime, as in: 此值使其进入运行时,如:

const x = Fields.User; // makes it to the emitted JS

and is similar to the value: 并且类似于值:

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

const xLike = FieldsLike.User; // makes it to the emitted JS;

But it also brings into scope a type named Fields , which is equivalent to the union of the property values in the Fields object. 但它也带来了为范围命名类型 Fields ,这相当于在属性值的联合 Fields对象。 This type is erased with the rest of the type system when JS is emitted, but can be accessed at design time via type annotations and using IntelliSense, as in: 发出JS时,此类型将与其他类型系统一起删除 ,但可以在设计时通过类型注释和使用IntelliSense进行访问,如下所示:

const y: Fields = x; // the "Fields" annotation is the type

and is similar to the type 并类似于类型

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

This is the type you're looking for; 这是您要寻找的类型; see below. 见下文。

By the way, the enum also acts as a namespace with exported types for each enum member: 顺便说一句,枚举充当每个枚举成员导出类型的名称空间:

const z: Fields.Password = Fields.Password; // type and value

(so the Fields.Password on the left is the name of a type , while the Fields.Password on the right is the name of a value ). (因此,左侧的Fields.Password类型的名称,而右侧的Fields.Password的名称)。 Thus the types accessible under Fields are similar to the namespace: 因此,在“ 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

Whew, that means just using the enum Fields { ... } definition give us the behavior of const FieldsLike = ... , type FieldsLike = ... , and namespace FieldsLike all at once. 简而言之,这意味着仅使用enum Fields { ... }定义就可以一次获得const FieldsLike = ...type FieldsLike = ...namespace FieldsLike

Let's back up... the type you were looking for, the union of all properties under the Fields enum, is already a type named Fields . 让我们备份一下...您要查找的类型,即Fields枚举下所有属性的并集,已经是一个名为Fields的类型。 (Okay, I changed the name of your FieldsMap to Fields ), and you can use it directly: (好的,我将您的FieldsMap的名称更改为Fields ),您可以直接使用它:

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;
  }
};

Okay, hope that helps. 好的,希望对您有所帮助。 Good luck! 祝好运!

Link to code 链接到代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM