javascript - Finnes det en (bedre) kortform for TypeScripts strengenummer eller objektlitteraler?
TypeScript-enumerasjoner ser slik ut:
enum Direction {
Up = "Up",
Down = "Down",
Left = "Left",
Right = "Right"
}
Enum-deklarasjoner som disse virker for meg som unødvendig arbeid. Spesielt med DRY-prinsippet i tankene. Finnes det ikke en snarvei for deklarasjoner som dette slik at jeg ikke trenger å gjenta verdiene når de er like nøklene? Selvfølgelig kunne jeg brukt numeriske enums, men de har den ulempen at ingen meningsfulle verdier er til stede under feilsøking.
For eksempel som objekt-literal forkortelsen fra ES6:
firstname = 'firstname';
lastname = 'lastname';
fullname = {
firstname,
lastname
}
Men selv med denne kortdefinisjonen må jeg fortsatt skrive for eksempel firstname tre ganger. Finnes det ikke en enklere måte?
Det hadde vært fint om noe sånt ville fungere:
// for enums:
string_enum Direction {
Up,
Down,
Left,
Right
}
// for object literals:
fullname: {
'firstname',
'lastname'
}
Svar #1
Dette er ikke akkurat det du spurte om; det lager ikke en ekte enum, men det fjerner duplikeringen og gir deg enum-lignende oppførsel. Vi skrev dette før ekte streng-enums var tilgjengelige og har stort sett sluttet å bruke dette siden dupliseringen i streng-enums kanskje ikke ser pen ut, men det forårsaker sjelden feil.
/**
* This creates a string enum. Use like so:
* const Ab = strEnum(['a', 'b']);
* type AbKeys = keyof typeof Ab;
* @param keys keys in the enum
* @returns enum object
*/
export function createStringEnum<T extends string>(keys: T[]): {[K in T]: K} {
return keys.reduce((res, key) => {
res[key] = key;
return res;
}, Object.create(null));
}
I det ovennevnte tilfellet er AbKeys typen du kan bruke når du tar imot ett av disse objektene. Merk at dette ikke er en ekte enum fordi du kan sende inn strengene og kompilatoren vil være fornøyd, noe som ikke ville vært tilfelle med enums
Eksempel
const Ab = createStringEnum(['a', 'b']);
type AbKeys = keyof typeof Ab;
function choose(key: AbKeys) {
if (key === Ab.a) {
return 'A'
}
return 'B';
}
// Type error
console.log(Ab.c);
// OK
console.log(choose(Ab.b));
// A true string enum wouldn't allow this
console.log(choose('a'));
// At least, it does't allow this...
function test (a: string) {
console.log(choose(a));
}
Se eksempel på TypeScript-lekeplassen
Svar #2
Siden TypeScript 3.4 kan du bruke const-påstander.
Selv om det ikke er en enum, liker jeg å bruke et array slik:
const DIRECTIONS = ["Up", "Down", "Left", "Right"] as const
type Direction = typeof DIRECTIONS[number]
function goTo(direction: Direction) {
// ...
}
goTo(" // with that open quote, you would see a list of the string literals
Du får ikke fordelen av å ha et objekt som en "representant" for å få tilgang til strengene (f.eks. Direction.Up), men med hvilken som helst moderne IDE-konfigurasjon for TypeScript, vil du få robust autofullføring og typedekning.
