如何在TypeScript中合并两个枚举

bes*_*ant 15 merge enums types typescript typescript2.0

假设我有两个枚举,如下面的Typescript中所述,那么我如何合并它们

enum Mammals {
    Humans,
    Bats,
    Dolphins
}

enum Reptiles {
    Snakes,
    Alligators,
    Lizards
}

export default Mammals & Reptiles // For Illustration purpose, Consider both the Enums have been merged.
Run Code Online (Sandbox Code Playgroud)

现在,当我importexported value另一个文件中,我应该能够从两个枚举访问值.

import animalTypes from "./animalTypes"

animalTypes.Humans //valid

animalTypes.Snakes // valid
Run Code Online (Sandbox Code Playgroud)

如何在Typescript中实现此类功能?

Arn*_*and 16

我不会提出合并到枚举的解决方案(我找不到合适的方法)

但是如果你想要从你使用它的方式表现得像枚举,你仍然可以在javascript中使用合并对象.

enum Mammals {
    Humans = 'Humans',
    Bats = 'Bats',
    Dolphins = 'Dolphins',
}

enum Reptiles {
  Snakes = 'Snakes',
  Alligators = 'Alligators',
  Lizards = 'Lizards',
}

const Animals = {
   ...Mammals,
   ...Reptiles,
}

type Animals = Mammals | Reptiles
Run Code Online (Sandbox Code Playgroud)

然后你可以使用Animals.Snakes或Animals.Dolphins,两者都应该正确输入并作为枚举

  • 添加`类型动物=哺乳动物| 爬行动物;来自@Porkishka的答案,它可以正常工作并通过类型检查 (2认同)
  • 如果您同时导出变量和类型,则不会有任何问题 (2认同)

Thé*_*ter 12

合并问题:

  • 相同的值=>值被覆盖
  • 相同的键=>键被覆盖

  • ?具有相同值的枚举(=>值被覆盖)

enum AA1 {
  aKey, // = 0
  bKey // = 1
}
enum BB1 {
  cKey, // = 0
  dKey // = 1
}
Run Code Online (Sandbox Code Playgroud)
  • ?具有相同键的枚举(=>键被覆盖)
enum AA2 {
  aKey = 1
}
enum BB2 {
  aKey = 2
}
Run Code Online (Sandbox Code Playgroud)
  • ?好
enum AA3 {
  aKey, // = 0
  bKey // = 1
}
enum BB3 {
  cKey = 2,
  dKey // = 3
}
Run Code Online (Sandbox Code Playgroud)
  • ?也不错
enum AA4 {
  aKey = 'Hello',
  bKey = 0,
  cKey // = 1
}
enum BB4 {
  dKey = 2,
  eKey = 'Hello',
  fKey = 'World'
}
Run Code Online (Sandbox Code Playgroud)

注: aKey = 'Hello'eKey = 'Hello'工作,因为有一个字符串值,枚举不具有这种价值的关键

// For aKey = 'Hello', key is working
type aa4aKey = AA4.aKey; // = AA4.aKey
// value is not.
type aa4aValue = AA4.Hello; // ? Namespace 'AA4' has no exported member 'Hello'
type aa4aValue2 = AA4['Hello']; // ? Property 'Hello' does not exist on type 'AA4'

console.log(AA4); // { 0: 'bKey', 1: 'cKey', aKey: 'Hello', bKey: 0, cKey: 1 }
console.log(BB4); // { 2: 'dKey', dKey: 2, eKey: 'Hello', fKey: 'World' }
Run Code Online (Sandbox Code Playgroud)

合并

  • ?使用联合类型
type AABB1 = AA4 | BB4; // = AA4 | BB4
type AABB1key = AABB1['aKey']; // = never
type AABB1key2 = AABB1.aKey; // ? 'AABB1' only refers to a type, but is being used as a namespace here. ts(2702)
Run Code Online (Sandbox Code Playgroud)
  • ?使用交集类型
type AABB1 = AA4 & BB4; // = never
type AABB1key = AABB1['aKey']; // = never
Run Code Online (Sandbox Code Playgroud)
  • ?使用具有typeof的交集类型
type AABB2 = (typeof AA4) & (typeof BB4); // = typeof AA4 & typeof BB4
type AABB2key = AABB2['aKey']; // = AA4.aKey
Run Code Online (Sandbox Code Playgroud)
  • ?使用js复制
const aabb1 = { ...AA4, ...BB4 };
const aabb2 = Object.assign({}, AA4, BB4); // also work
// aabb1 = {
// 0: 'bKey',
// 1: 'cKey',
// 2: 'dKey',
// aKey: 'Hello',
// bKey: 0,
// cKey: 1,
// dKey: 2,
// eKey: 'Hello',
// fKey: 'World' }
Run Code Online (Sandbox Code Playgroud)
  • ?将typeof与js副本一起使用
const aabb = { ...AA4, ...BB4 };
type TypeofAABB = typeof aabb;
// type TypeofAABB = {
// [x: number]: string;
// dKey: BB4.dKey;
// eKey: BB4.eKey;
// fKey: BB4.fKey;
// aKey: AA4.aKey;
// bKey: AA4.bKey;
// cKey: AA4.cKey;
// };
Run Code Online (Sandbox Code Playgroud)

提示:您可以为类型和值使用相同的名称

const merged = { ...AA4, ...BB4 };
type merged = typeof merged;

const aValue = merged.aKey;
type aType = merged['aKey'];
Run Code Online (Sandbox Code Playgroud)

你的情况

如果要合并两个枚举,则有〜3个选择:

1.使用字符串枚举

enum Mammals {
  Humans = 'Humans',
  Bats = 'Bats',
  Dolphins = 'Dolphins'
}

enum Reptiles {
  Snakes = 'Snakes',
  Alligators = 'Alligators',
  Lizards = 'Lizards'
}

export const Animals = { ...Mammals, ...Reptiles };
export type Animals = typeof Animals;
Run Code Online (Sandbox Code Playgroud)

2.使用唯一编号

enum Mammals {
  Humans = 0,
  Bats,
  Dolphins
}

enum Reptiles {
  Snakes = 2,
  Alligators,
  Lizards
}

export const Animals = { ...Mammals, ...Reptiles };
export type Animals = typeof Animals;
Run Code Online (Sandbox Code Playgroud)

3.使用嵌套枚举

enum Mammals {
  Humans,
  Bats,
  Dolphins
}

enum Reptiles {
  Snakes,
  Alligators,
  Lizards
}

export const Animals = { Mammals, Reptiles };
export type Animals = typeof Animals;

const bats = Animals.Mammals.Bats; // = 1
const alligators = Animals.Reptiles.Alligators; // = 1
Run Code Online (Sandbox Code Playgroud)

注意:您还可以将嵌套枚举与以下代码合并。小心不要重复的值!

type Animal = {
  [K in keyof Animals]: {
    [K2 in keyof Animals[K]]: Animals[K][K2]
  }[keyof Animals[K]]
}[keyof Animals];

const animal: Animal = 0 as any;

switch (animal) {
  case Animals.Mammals.Bats:
  case Animals.Mammals.Dolphins:
  case Animals.Mammals.Humans:
  case Animals.Reptiles.Alligators:
  case Animals.Reptiles.Lizards:
  case Animals.Reptiles.Snakes:
    break;
  default: {
    const invalid: never = animal; // no error
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 多么全面的答案啊! (7认同)
  • 例如 1 和 2,您应该执行“export type Animals = Mammals |”,而不是“export type Animals = typeof Animals;” 爬行动物`; 这样哺乳动物就可以分配给动物 (7认同)
  • 我无法将嵌套枚举与开关一起使用 (2认同)
  • @ShashankVivek 基本上是复制/粘贴表情符号(符号部分)。它们是书面解释的重要资源:) (2认同)

gom*_*osg 6

枚举,接口和类型-合并枚举的有效解决方案

这里令人困惑的是类型与值。

  • 如果定义一个letconst等),它将具有一个值加上一些计算出但未单独命名的类型。
  • 如果您定义typeinterface,它将创建一个命名类型,但不会以任何方式在最终JS中输出或考虑该类型。仅在编写应用程序时有用。
  • 如果enum在Typescript中创建一个,它将创建一个可以使用的静态类型名称以及一个可以输出到JS的实际对象。

从TS手册中:

使用枚举很简单:只需从枚举本身访问任何成员作为属性,然后使用枚举的名称声明类型。

因此,如果您有Object.assign()两个枚举,它将创建一个新的合并(对象),而不是一个新的命名类型。

由于已经enum不复存在了,因此您失去了拥有值和命名类型的优势,但是仍可以创建单独的类型名称作为解决方法。

幸运的是,您可以为值和类型使用相同的名称,并且如果导出它们,TS会同时导入两者。

// This creates a merged enum, but not a type
const Animals = Object.assign({}, Mammals, Reptiles);

// Workaround: create a named type (typeof Animals won't work here!)
type Animals = Mammals | Reptiles;
Run Code Online (Sandbox Code Playgroud)

TS游乐场链接


Tao*_*Tao 5

TypeScript 枚举不仅包含您定义的键,还包含数值倒数,例如:

Mammals.Humans === 0 && Mammals[0] === 'Humans'
Run Code Online (Sandbox Code Playgroud)

现在,如果您尝试合并它们 - 例如与Object#assign- 您最终会得到两个具有相同数值的键:

const AnimalTypes = Object.assign({}, Mammals, Reptiles);
console.log(AnimalTypes.Humans === AnimalTypes.Snakes) // true
Run Code Online (Sandbox Code Playgroud)

我想这不是你想要的。

防止这种情况的一种方法是手动将值分配给枚举并确保它们不同:

enum Mammals {
    Humans = 0,
    Bats = 1,
    Dolphins = 2
}

enum Reptiles {
    Snakes = 3,
    Alligators = 4,
    Lizards = 5
}
Run Code Online (Sandbox Code Playgroud)

或不那么明确但在其他方面等效:

enum Mammals {
    Humans,
    Bats,
    Dolphins
}

enum Reptiles {
    Snakes = 3,
    Alligators,
    Lizards
}
Run Code Online (Sandbox Code Playgroud)

无论如何,只要您确保合并的枚举具有不同的键/值集,您就可以将它们与Object#assign.

游乐场演示


小智 5

您需要使用字符串 id 来表示枚举值和正确的导出类型:

enum Mammals {
  Humans = 'humans',
  Bats = 'bats',
  Dolphins = 'dolphins',
}

enum Reptiles {
  Snakes = 'snakes',
  Alligators = 'alligators',
  Lizards = 'lizards',
}

export const Animals = { ...Mammals, ...Reptiles };
type TAnimalsKeys = keyof typeof Animals;
export type TAnimal = typeof Animals[TAnimalsKeys];
Run Code Online (Sandbox Code Playgroud)