angular - Käytä objektin literaalia TypeScriptin enum-arvoina
Minulla on enum:
export enum PizzaSize {
SMALL = 0,
MEDIUM = 1,
LARGE = 2
}
Mutta tässä haluaisin käyttää jotakin arvojoukkoa: esim. SMALL haluaisin sanoa, että sillä on key arvo 0 ja value arvo 100. Yritän käyttää:
export enum PizzaSize {
SMALL = { key: 0, value: 100 },
// ...
}
Mutta TypeScript ei hyväksy tätä. Miten voin tehdä tämän?
Vastaus #1
TypeScript tukee vain numeerisia tai merkkijonopohjaisia enum -tyyppejä, joten sinun täytyy jäljitellä olioenumia luokalla (joka sallii sen käyttämisen tyyppeinä funktiomääritelmässä):
export class PizzaSize {
static readonly SMALL = new PizzaSize('SMALL', 'A small pizza');
static readonly MEDIUM = new PizzaSize('MEDIUM', 'A medium pizza');
static readonly LARGE = new PizzaSize('LARGE', 'A large pizza');
// private to disallow creating other instances of this type
private constructor(private readonly key: string, public readonly value: any) {
}
toString() {
return this.key;
}
}
sitten voit käyttää ennalta määriteltyjä instansseja päästäksesi niiden value-arvoon:
const mediumVal = PizzaSize.MEDIUM.value;
tai mikä tahansa muu ominaisuus/ominaisuustyyppi, jonka saatat haluta määritellä PizzaSize:ssa.
ja kiitos toString()-ylikirjoituksen, pystyt myös tulostamaan enum-nimen/avaimen implisiittisesti objektista:
console.log(PizzaSize.MEDIUM); // prints 'MEDIUM'
Vastaus #2
Päivitys: löydät @Javaromen vastauksen alla, joka on hienostuneempi. Ehdotan, että käytät hänen tapaansa.
Jos sinun täytyy käyttää Typea, yritä lisätä hieman koodia. käyttö: getPizzSizeSpec(PizzaSize.small).value
enum PizzaSize {
small,
medium,
large
}
interface PizzaSizeSpec {
key: number,
value: number
}
function getPizzaSizeSpec(pizzaSize: PizzaSize): PizzaSizeSpec {
switch (pizzaSize) {
case PizzaSize.small:
return {key:0, value: 25};
case PizzaSize.medium:
return {key:0, value: 35};
case PizzaSize.large:
return {key:0, value: 50};
}
}
Vastaus #3
Typscript 3.4:stä alkaen voit käyttää yhdistelmää keyof typeof ja const -väittämiä luodaksesi olioita, jotka voivat olla samalla työturvallisia kuin enumeroinnit ja silti sisältää monimutkaisia arvoja.
Luomalla type, jolla on sama nimi kuin const:lla, voit saada samat kattavuustarkistukset kuin tavallisilla enum-tyypeillä.
Ainoa haittapuoli on, että tarvitset jonkin avaimen monimutkaisessa objektissa (käytän tässä value), joka pitää enum-jäsenen nimen (jos joku pystyy keksimään apufunktion, joka voi rakentaa nämä objektit tyypin turvallisella tavalla, haluaisin nähdä sen! En onnistunut saamaan sellaista toimimaan).
export const PizzaSize = {
small: { value: 'small', key: 0, size: 25 },
medium: { value: 'medium', key: 1, size: 35 },
large: { value: 'large', key: 2, size: 50 },
} as const
export type PizzaSize = keyof typeof PizzaSize
// if you remove any of these cases, the function won't compile
// because it can't guarantee that you've returned a string
export function order(p: PizzaSize): string {
switch (p) {
case PizzaSize.small.value: return 'just for show'
case PizzaSize.medium.value: return 'just for show'
case PizzaSize.large.value: return 'just for show'
}
}
// you can also just hardcode the strings,
// they'll be type checked
export function order(p: PizzaSize): string {
switch (p) {
case 'small': return 'just for show'
case 'medium': return 'just for show'
case 'large': return 'just for show'
}
}
Muissa tiedostoissa tätä voidaan käyttää yksinkertaisesti, tuo vain PizzaSize.
import { PizzaSize } from './pizza'
console.log(PizzaSize.small.key)
type Order = { size: PizzaSize, person: string }
Huomaa myös, kuinka jopa objektit, jotka yleensä ovat muutettavissa, eivät voi muuttua as const -syntaksia käyttäen.
const Thing = {
ONE: { one: [1, 2, 3] }
} as const
// this won't compile!! Yay!!
Thing.ONE.one.splice(1, 0, 0)
Vastaus #4
Luulen, että päästäksesi siihen, mitä haluat, tällainen toimii
interface PizzaInfo {
name: string;
cost_multiplier: number;
}
enum PizzaSize {
SMALL,
MEDIUM,
LARGE,
}
const pizzas: Record<PizzaSize, PizzaInfo> = {
[PizzaSize.SMALL]: { name: "Small", cost_multiplier: 0.7 },
[PizzaSize.MEDIUM]: { name: "Medium", cost_multiplier: 1.0 },
[PizzaSize.LARGE]: { name: "Large", cost_multiplier: 1.5 },
};
const order = PizzaSize.SMALL;
console.log(pizzas[order].name); // "Small"
