tyypit - Kuinka yhdistää kaksi enumia TypeScriptissä
Oletetaan, että minulla on kaksi enumerointia alla kuvatulla tavalla Typescriptissä, miten yhdistän ne sitten
enum Mammals {
Humans,
Bats,
Dolphins
}
enum Reptiles {
Snakes,
Alligators,
Lizards
}
export default Mammals & Reptiles // For Illustration purpose, Consider both the Enums have been merged.
Nyt, kun tuon viedyn arvon toisessa tiedostossa, minun pitäisi pystyä käyttämään arvoja molemmista enum-tyypeistä.
import animalTypes from "./animalTypes"
animalTypes.Humans //valid
animalTypes.Snakes // valid
Kuinka voin saavuttaa tällaisen toiminnallisuuden TypeScriptissä?
Vastaus #1
Ongelmia yhdistämisen kanssa:
- samat arvot => arvot korvataan
samat avaimet => avaimet ylikirjoitetaan
❌ Enumit, joilla on samat arvot (=> arvot ylikirjoitetaan)
enum AA1 {
aKey, // = 0
bKey // = 1
}
enum BB1 {
cKey, // = 0
dKey // = 1
}
- ❌ Enumit, joilla on samat avaimet (=> avaimet ylikirjoitetaan)
enum AA2 {
aKey = 1
}
enum BB2 {
aKey = 2
}
- ✅ Hyvä
enum AA3 {
aKey, // = 0
bKey // = 1
}
enum BB3 {
cKey = 2,
dKey // = 3
}
- ✅ Myös hyvä
enum AA4 {
aKey = 'Hello',
bKey = 0,
cKey // = 1
}
enum BB4 {
dKey = 2,
eKey = 'Hello',
fKey = 'World'
}
Huomautus: aKey='Hello' ja eKey='Hello' toimivat, koska merkkijonon arvolla oleva enum ei omaa tätä arvoa avaimena
// 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' }
Yhdistäminen
- ❌ union-tyyppien käyttö
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)
- ❌ käyttämällä leikkaustyyppejä
type AABB1 = AA4 & BB4; // = never
type AABB1key = AABB1['aKey']; // = never
- ✅ käyttämällä leikkaustyyppejä typeof:n kanssa
type AABB2 = (typeof AA4) & (typeof BB4); // = typeof AA4 & typeof BB4
type AABB2key = AABB2['aKey']; // = AA4.aKey
- ✅ käyttämällä js kopioi
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' }
- ✅ typeofin käyttäminen js-kopiolla
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;
// };
Vinkki: voit käyttää samaa nimeä tyypille ja arvolla
const merged = { ...AA4, ...BB4 };
type merged = typeof merged;
const aValue = merged.aKey;
type aType = merged['aKey'];
Tapauksesi
Jos haluat yhdistää kaksi enumiasi, sinulla on ~3 vaihtoehtoa:
1. Merkkijonoenumien käyttäminen
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. Yksilöllisten numeroiden käyttäminen
enum Mammals {
Humans = 0,
Bats,
Dolphins
}
enum Reptiles {
Snakes = 2,
Alligators,
Lizards
}
export const Animals = { ...Mammals, ...Reptiles };
export type Animals = typeof Animals;
3. Nimettyjen luokkien käyttäminen
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
Huomautus: voit myös yhdistää sisäkkäiset enumit seuraavalla koodilla. Varmista, ETTET saa päällekkäisiä arvoja tehdessäsi niin!
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
}
}
Vastaus #2
Jos haluat jotain käyttäytyvän kuten enum sen käyttötavan perusteella, voit silti käyttää yhdistettyä objektia JavaScriptissä.
enum Mammals {
Humans = 'Humans',
Bats = 'Bats',
Dolphins = 'Dolphins',
}
enum Reptiles {
Snakes = 'Snakes',
Alligators = 'Alligators',
Lizards = 'Lizards',
}
const Animals = {
...Mammals,
...Reptiles,
}
type Animals = Mammals | Reptiles
Sitten voisit käyttää Animals.Snakes tai Animals.Dolphins, ja molempien pitäisi olla oikein typennettyjä ja toimia enumina
Vastaus #3
Enumit, rajapinnat ja tyypit - toimiva ratkaisu enumien yhdistämiseen
Se, mikä täällä on hämmentävää, ovat tyypit vs. arvot.
- Jos määrittelet arvon (
let,constjne.), sillä on arvo sekä joitakin laskettuja mutta erikseen nimeämättömiä tyyppejä. - Jos määrittelet
typetaiinterface, se luo nimetyntyypin, mutta sitä ei tulosteta eikä sitä oteta huomioon lopullisessa JS:ssä millään tavalla. Se auttaa vain sovelluksesi kirjoittamisessa. - Jos luot
enumTypescriptissä, se luo staattisen tyypin nimen, jota voit käyttää plus todellisen objektin, joka tuotetaan JS:ään ja jota voit käyttää.
TS-käsikirjasta:
Enumia käyttämällä on yksinkertaista: pääset käsiksi mihin tahansa jäseneseen suoraan enumista ja määrittelet tyypit käyttämällä enumin nimeä.
Joten, jos käytät Object.assign() kahta enumia, se luo uuden, yhdistetyn arvon (objektin), mutta ei uutta nimettyä tyyppiä.
Koska se ei ole enää enum, menetät edun, joka tulee siitä, että sillä on arvo ja nimetty tyyppi, mutta voit silti luoda erillisen tyyppinimen kiertotapana.
Onneksi voit käyttää samaa nimeä sekä arvolle että tyypille, ja TS tuo molemmat, jos viet ne.
// 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-leikkikentän linkki
