如何在 TypeScript 中合并两个枚举
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/48478361/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to merge two enums in TypeScript
提问by besrabasant
Suppose I have two enums as described below in Typescript, then How do I merge them
假设我有两个枚举,如下面的 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.
Now, when I import
the exported value
in another file, I should be able to access values from both the enums.
现在,当我import
在exported value
另一个文件中,我应该能够从两个枚举访问值。
import animalTypes from "./animalTypes"
animalTypes.Humans //valid
animalTypes.Snakes // valid
How can I achieve such functionality in Typescript?
如何在 Typescript 中实现这样的功能?
回答by Théry Fouchter
Problems with the merge:
合并问题:
- same values => values are overwritten
same keys => keys are overwritten
? Enums with same values (=> values are overwritten)
- 相同的值 => 值被覆盖
相同的键 => 键被覆盖
? 具有相同值的枚举(=> 值被覆盖)
enum AA1 {
aKey, // = 0
bKey // = 1
}
enum BB1 {
cKey, // = 0
dKey // = 1
}
- ? Enums with the same keys (=> keys are overwritten)
- ? 具有相同键的枚举(=> 键被覆盖)
enum AA2 {
aKey = 1
}
enum BB2 {
aKey = 2
}
- ? Good
- ? 好的
enum AA3 {
aKey, // = 0
bKey // = 1
}
enum BB3 {
cKey = 2,
dKey // = 3
}
- ? Also Good
- ? 也很好
enum AA4 {
aKey = 'Hello',
bKey = 0,
cKey // = 1
}
enum BB4 {
dKey = 2,
eKey = 'Hello',
fKey = 'World'
}
Note:
aKey = 'Hello'
and eKey = 'Hello'
work because the enum with a string value doesn't has this value as key
注意:
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' }
The merge
合并
- ? using union types
- ? 使用联合类型
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)
- ? using intersection types
- ? 使用交叉点类型
type AABB1 = AA4 & BB4; // = never
type AABB1key = AABB1['aKey']; // = never
- ? using intersection types with typeof
- ? 使用带有 typeof 的交集类型
type AABB2 = (typeof AA4) & (typeof BB4); // = typeof AA4 & typeof BB4
type AABB2key = AABB2['aKey']; // = AA4.aKey
- ? using js copy
- ? 使用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' }
- ? using typeof with a js copy
- ? 将 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;
// };
Tip: you can use the same name for a type and a value
提示:您可以对类型和值使用相同的名称
const merged = { ...AA4, ...BB4 };
type merged = typeof merged;
const aValue = merged.aKey;
type aType = merged['aKey'];
Your case
你的情况
If you want to merge your 2 enums you have ~3 choices:
如果你想合并你的 2 个枚举,你有 ~3 个选择:
1. Using string enums
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;
2. Using unique numbers
2. 使用唯一号码
enum Mammals {
Humans = 0,
Bats,
Dolphins
}
enum Reptiles {
Snakes = 2,
Alligators,
Lizards
}
export const Animals = { ...Mammals, ...Reptiles };
export type Animals = typeof Animals;
3. Using nested enums
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
Note: you can also merge the nested enums with the following code. Take care to NOT have duplicated values if you do that!
注意:您还可以使用以下代码合并嵌套的枚举。如果这样做,请注意不要有重复的值!
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
}
}
回答by Arnaud Bertrand
I'm not going to propose a solution to merge to enums (I couldn't find a proper way to do it)
我不打算提出合并到枚举的解决方案(我找不到合适的方法来做到这一点)
But if you want something behaving like an enum from the way you consume it, you could still use merged object in javascript.
但是,如果您希望从您使用它的方式中获得类似于枚举的行为,您仍然可以在 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
Then you could use Animals.Snakes or Animals.Dolphins and both should be properly typed and work as an enum
然后你可以使用 Animals.Snakes 或 Animals.Dolphins 并且两者都应该正确输入并作为枚举工作
回答by gombosg
Enums, interfaces and types - a working solution for merging enums
枚举、接口和类型 - 合并枚举的工作解决方案
What's confusing here is types vs. values.
这里令人困惑的是类型与值。
- If you define a value(
let
,const
etc.) it will have a value plus some computed but not separately named type. - If you define a
type
orinterface
, it will create a named type but that will not be outputted or considered in the final JS in any way. It only helps when writing your app. - If you create an
enum
in Typescript, it creates a static type name that you can use plusa real object outputted to JS that you can use.
- 如果你定义一个值(
let
,const
等)将有一个价值加上一些计算,但不单独命名的类型。 - 如果定义了
type
orinterface
,它将创建一个命名类型,但不会以任何方式在最终的 JS 中输出或考虑。它仅在编写您的应用程序时有所帮助。 - 如果您
enum
在 Typescript 中创建一个,它会创建一个您可以使用的静态类型名称以及一个输出到您可以使用的 JS 的真实对象。
From the TS handbook:
来自 TS 手册:
Using an enum is simple: just access any member as a property off of the enum itself, and declare types using the name of the enum.
使用枚举很简单:只需将任何成员作为枚举本身的属性访问,并使用枚举的名称声明类型。
So, if you Object.assign()
two enums, it will create a new, merged value(object), but not a new named type.
因此,如果您使用Object.assign()
两个枚举,它将创建一个新的合并值(对象),而不是一个新的命名类型。
Since it's not an enum
anymore, you lose the advantage of having a value and a named type, but you can still create a separate type name as a workaround.
由于它不再是一个enum
,因此您失去了拥有值和命名类型的优势,但您仍然可以创建一个单独的类型名称作为解决方法。
Fortunately, you can have the same name for the value and the type, and TS will import both if you export them.
幸运的是,您可以为值和类型使用相同的名称,如果您导出它们,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;
回答by Tao
A TypeScript enum not only contains the keys you define but also the numerical inverse, so for example:
TypeScript 枚举不仅包含您定义的键,还包含数值倒数,例如:
Mammals.Humans === 0 && Mammals[0] === 'Humans'
Now, if you try to merge them -- for example with Object#assign
-- you'd end up with two keys having the same numerical value:
现在,如果您尝试合并它们 - 例如与Object#assign
- 您最终会得到两个具有相同数值的键:
const AnimalTypes = Object.assign({}, Mammals, Reptiles);
console.log(AnimalTypes.Humans === AnimalTypes.Snakes) // true
And I suppose that's not what you want.
我想那不是你想要的。
One way to prevent this, is to manually assign the values to the enum and make sure that they are different:
防止这种情况的一种方法是手动将值分配给枚举并确保它们不同:
enum Mammals {
Humans = 0,
Bats = 1,
Dolphins = 2
}
enum Reptiles {
Snakes = 3,
Alligators = 4,
Lizards = 5
}
or less explicit but otherwise equivalent:
或不那么明确但在其他方面等效:
enum Mammals {
Humans,
Bats,
Dolphins
}
enum Reptiles {
Snakes = 3,
Alligators,
Lizards
}
Anyway, as long as you make sure that the enums you merge have different key/value sets you can merge them with Object#assign
.
无论如何,只要您确保合并的枚举具有不同的键/值集,您就可以将它们与Object#assign
.
回答by waterplea
I'd say the proper way to do it would be defining a new type:
我会说正确的方法是定义一个新类型:
enum Mammals {
Humans = 'Humans',
Bats = 'Bats',
Dolphins = 'Dolphins',
}
enum Reptiles {
Snakes = 'Snakes',
Alligators = 'Alligators',
Lizards = 'Lizards',
}
type Animals = Mammals | Reptiles;
回答by Bal mukund kumar
Try this enumerations example ------
试试这个枚举示例 ------
Enums or enumerations are a new data type supported in TypeScript
枚举或枚举是 TypeScript 支持的新数据类型
enum PrintMedia {
Newspaper = 1,
Newsletter,
Magazine,
Book
}
function getMedia(mediaName: string): PrintMedia {
if ( mediaName === 'Forbes' || mediaName === 'Outlook') {
return PrintMedia.Magazine;
}
}
let mediaType: PrintMedia = getMedia('Forbes');