C'è un modo per avere un enum TypeScript compatibile con le stringhe di JSON?Typescript `enum` dalla stringa JSON
Ad esempio:
enum Type { NEW, OLD }
interface Thing { type: Type }
let thing:Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW); // false
avrei comething.type == Type.NEW
per essere vero. O più specificamente, vorrei poter specificare i valori enum
da definire come stringhe, non numeri.
Sono consapevole del fatto che posso utilizzare thing.type.toString() == Type[Type.NEW]
ma questo è ingombrante e sembra rendere l'annotazione del tipo enum confusa e fuorviante, che sconfigge il suo scopo. Il JSON è tecnicamente non fornendo un valore enum valido, quindi non dovrei digitare la proprietà all'enumerazione.
Quindi quello che sto facendo attualmente invece utilizza un tipo di stringa con costanti statiche:
const Type = { NEW: "NEW", OLD: "OLD" }
interface Thing { type: string }
let thing:Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW); // true
Questo mi fa l'uso che voglio, ma il tipo di annotazione string
è troppo ampio e soggetto a errori.
Sono un po 'sorpreso dal fatto che un superset di JavaScript non abbia enumerazioni basate su stringhe. Mi sto perdendo qualcosa? C'è un modo diverso per farlo?
Aggiornamento TS 1.8
Utilizzando string literal types è un'altra alternativa (grazie @basaret), ma per ottenere l'utilizzo enum-come desiderato (sopra) richiede che definisce i valori due volte: una volta in un tipo letterale di stringa, e una volta come un valore (costante o namespace):
type Type = "NEW" | "OLD";
const Type = {
NEW: "NEW" as Type,
OLD: "OLD" as Type
}
interface Thing { type: Type }
let thing:Thing = JSON.parse(`{"type": "NEW"}`);
alert(thing.type === Type.NEW); // true
Questo funziona, ma prende un sacco di boilerplate, basta che io non lo uso più o il tempo Per ora spero che lo proposal for string enums
alla fine formuli la roadmap.
Aggiorna TS 2.1
Il nuovo keyof
type lookup consente al tipo letterale stringa tratte dai tasti di un const o spazio, che rende la definizione un po meno ridondante:
namespace Type {
export const OLD = "OLD";
export const NEW = "NEW";
}
type Type = keyof typeof Type;
interface Thing { type: Type }
const thing: Thing = JSON.parse('{"type": "NEW"}');
thing.type == Type.NEW // true
Aggiornamento T S 2.4
TypeScript 2.4 added support for string enums!L'esempio precedente diventa:
enum Type {
OLD = "OLD",
NEW = "NEW"
}
interface Thing { type: Type }
const thing: Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW) // true
Questo sembra quasi perfetto, ma c'è ancora un po 'di mal di cuore:
- È ancora devono scrivere il valore due volte, vale a dire
OLD = "OLD"
, e non c'è alcuna convalida che non hai un errore di battitura, comeNEW = "MEW"
... questo mi ha già morso in codice reale. Ci sono alcune stranezze (forse degli errori?) Con il modo in cui l'enum è controllato, non è solo una stenografia di tipo letterale, che è ciò che sarebbe veramente corretto. Alcuni problemi che ho urtato:
enum Color { RED = "RED", BLUE = "BLUE", GREEN = "GREEN" } type ColorMap = { [P in Color]: number; } declare const color: Color; declare const map: ColorMap; map[color] // Error: Element implicitly has an 'any' type because type 'ColorMap' has no index signature. const red: Color = "RED"; // Type '"RED"' is not assignable to type 'Color'. const blue: Color = "BLUE" as "RED" | "BLUE" | "GREEN"; // Error: Type '"RED" | "BLUE" | "GREEN"' is not assignable to type 'Color'.
Il codice equivalente con
enum Color
sostituito da stringhe letterali tipi funzionano bene ...
Sì, credo di avere OCD su questo, voglio solo le mie enfole JS perfette. :)
Grazie! Vorrei aver saputo della "qualsiasi" asserzione prima. Ora sto provando TS 2.4 enum di stringhe, ed è abbastanza vicino a quello che volevo inizialmente ... ma ho trovato alcuni problemi con il modo in cui il tipo TS lo controlla ... – Aaron
@Aaron cool, felice di aiutare! Inoltre, potresti voler controllare il progetto [ts-enums] (https://github.com/LMFinney/ts-enums) in quanto rende la gestione di enum molto versatile e potente per molti casi d'uso –