web-dev-qa-db-ja.com

TypeScriptで2つの列挙型をマージする方法

TypeScriptで以下に説明するように2つの列挙型があるとし、それらをどのようにマージしますか

enum Mammals {
    Humans,
    Bats,
    Dolphins
}

enum Reptiles {
    Snakes,
    Alligators,
    Lizards
}

export default Mammals & Reptiles // For Illustration purpose, Consider both the Enums have been merged.

今、私がimport the exported value別のファイルでは、両方の列挙型の値にアクセスできるはずです。

import animalTypes from "./animalTypes"

animalTypes.Humans //valid

animalTypes.Snakes // valid

Typescriptでこのような機能を実現するにはどうすればよいですか?

13
besrabasant

列挙型にマージするソリューションを提案するつもりはありません(適切な方法を見つけることができませんでした)

しかし、あなたがそれを消費する方法からenumのように振る舞う何かが必要な場合は、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

次に、Animals.SnakesまたはAnimals.Dolphinsを使用できます。両方を適切に入力し、列挙型として機能する必要があります

12
Arnaud Bertrand

列挙型、インターフェース、型-列挙型をマージするための実用的なソリューション

ここで混乱しているのは、タイプと値です。

  • valueletconstなど)を定義すると、値に計算されたものの個別の名前付きタイプ。
  • typeまたはinterfaceを定義すると、名前付きタイプが作成されますが、出力または考慮されませんいずれにせよ、最終的なJSで。アプリの作成時にのみ役立ちます。
  • TypeScriptで enum を作成すると、使用できる静的な型名が作成されますplus使用できるJSに出力される実際のオブジェクト。

TSハンドブックから:

列挙型の使用は簡単です。列挙型自体のプロパティとして任意のメンバーにアクセスし、列挙型の名前を使用して型を宣言するだけです。

したがって、Object.assign() 2つの列挙型を作成すると、新しいマージされたvalue(オブジェクト)が作成されますが、新しい名前付きの型は作成されません。

これは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;

TSプレイグラウンドリンク

6
gombosg

マージの問題:

  • 同じ値=>値は上書きされます
  • 同じキー=>キーは上書きされます

  • same同じ値の列挙(=>値は上書きされます)

enum AA1 {
  aKey, // = 0
  bKey // = 1
}
enum BB1 {
  cKey, // = 0
  dKey // = 1
}
  • same同じキーを持つ列挙型(=>キーは上書きされます)
enum AA2 {
  aKey = 1
}
enum BB2 {
  aKey = 2
}
  • 良い
enum AA3 {
  aKey, // = 0
  bKey // = 1
}
enum BB3 {
  cKey = 2,
  dKey // = 3
}
  • ✅も良い
enum AA4 {
  aKey = 'Hello',
  bKey = 0,
  cKey // = 1
}
enum BB4 {
  dKey = 2,
  eKey = 'Hello',
  fKey = 'World'
}

注意: 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' }

マージ

  • unユニオン型の使用
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)
  • intersection交差点タイプの使用
type AABB1 = AA4 & BB4; // = never
type AABB1key = AABB1['aKey']; // = never
  • type typeofで交差タイプを使用する
type AABB2 = (typeof AA4) & (typeof BB4); // = typeof AA4 & typeof BB4
type AABB2key = AABB2['aKey']; // = AA4.aKey
  • j js copyを使用する
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' }
  • type 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;
// };

ヒント:タイプと値に同じ名前を使用できます

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

const aValue = merged.aKey;
type aType = merged['aKey'];

あなたの場合

2つの列挙型をマージする場合、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;

2.一意の番号を使用する

enum Mammals {
  Humans = 0,
  Bats,
  Dolphins
}

enum Reptiles {
  Snakes = 2,
  Alligators,
  Lizards
}

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

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

注:ネストされた列挙型を次のコードとマージすることもできます。それを行う場合は、値が重複しないように注意してください!

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
  }
}
6
Théry Fouchter

TypeScript列挙型には、定義したキーだけでなく、逆数値も含まれているため、たとえば次のようになります。

Mammals.Humans === 0 && Mammals[0] === 'Humans'

今、それらをマージしようとすると-たとえばObject#assign-同じ数値を持つ2つのキーになります。

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

そして、それはあなたが望むものではないと思います。

これを防ぐ1つの方法は、列挙型に値を手動で割り当て、それらが異なることを確認することです。

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

enum Reptiles {
    Snakes = 3,
    Alligators = 4,
    Lizards = 5
}

以下のように明示的ですが、それ以外は同等です:

enum Mammals {
    Humans,
    Bats,
    Dolphins
}

enum Reptiles {
    Snakes = 3,
    Alligators,
    Lizards
}

とにかく、マージする列挙型が異なるキー/値セットを持っていることを確認している限り、Object#assign

プレイグラウンドデモ

4
Tao

適切な方法は、新しい型を定義することだと思います。

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

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

type Animals = Mammals | Reptiles;
3
pokrishka