Czy istnieje sposób na wybranie wyliczenia TypeScript zgodnego z łańcuchami z JSON?Opis maszynowy `wyliczanie` z ciągu JSON
Na przykład:
enum Type { NEW, OLD }
interface Thing { type: Type }
let thing:Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW); // false
bym jakthing.type == Type.NEW
aby mogło być prawdziwe. A dokładniej, chciałbym móc określić wartości enum
, które mają być zdefiniowane jako ciągi, a nie liczby.
Jestem świadomy, że mogę używać thing.type.toString() == Type[Type.NEW]
, ale jest to uciążliwe i wydaje się, że adnotacja typu wyliczeniowego jest myląca i wprowadzająca w błąd, co jest sprzeczne z jej celem. JSON jest technicznie nie dostarczając prawidłową wartość wyliczenia, więc nie powinienem wpisywać właściwości do wyliczenia.
Więc co mam aktualnie robi zamiast używa typu string ze stałych statycznych:
const Type = { NEW: "NEW", OLD: "OLD" }
interface Thing { type: string }
let thing:Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW); // true
To dostaje mi użycie chcę, ale typ adnotacji string
jest zbyt szeroka i podatne na błędy.
Jestem nieco zaskoczony, że nadzbiór JavaScript nie ma wyrażeń opartych na ciągach znaków. Czy czegoś brakuje? Czy można to inaczej zrobić?
Aktualizacja TS 1,8
Korzystanie string literal types jest inny alternatywny (dzięki @basaret), ale aby uzyskać pożądany użycie enum-like (powyżej) wymaga definiowania wartości dwukrotnie: raz w łańcuch znaków typu, a raz jako wartość (stałą lub nazw):
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
To działa, ale zajmuje sporo boilerplate, tyle że nie używam go o najbardziej w tym czasie. Na razie mam nadzieję, że proposal for string enums
ostatecznie wykona mapę drogową.
Aktualizacja TS 2,1
Nowy keyof
type lookup pozwala na ciąg dosłownym typu mają być generowane z klawiszy const lub nazw, co czyni definicji trochę mniej zbędny:
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
Aktualizacja T S 2.4
TypeScript 2.4 added support for string enums!Powyższy przykład postać:
enum Type {
OLD = "OLD",
NEW = "NEW"
}
interface Thing { type: Type }
const thing: Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW) // true
To wygląda prawie doskonały, ale jeszcze trochę strapienie:
- Ty nadal trzeba pisać wartość dwukrotnie, tj
OLD = "OLD"
, i nie ma walidacji że nie masz literówki, jakNEW = "MEW"
... to już mnie ugryzło w prawdziwym kodzie. Istnieje kilka osobliwości (być może błędów?) Z tym, jak sprawdzane jest wyliczenie typu, a nie tylko skrótem typu literowego, co jest naprawdę poprawne. Niektóre kwestie ja zderzyłem:
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'.
Odpowiednik kodu z
enum Color
zastąpiony ciągiem dosłowne rodzaje działać dobrze ...
Tak, myślę, że mam OCD o tym, po prostu chcę moje doskonałe wyliczenia JS. :)
Dzięki! Szkoda, że nie wiedziałem wcześniej o twierdzeniu "any". Teraz próbuję TS 2.4 string wylicza, i jest to dość zbliżone do tego, co pierwotnie chciałem ... ale znalazłem pewne problemy ze sposobem, w jaki sprawdza go typ TS ... – Aaron
@Aaron fajny, z przyjemnością pomogę! Możesz również sprawdzić projekt [ts-enums] (https://github.com/LMFinney/ts-enums), ponieważ sprawia on, że obsługa enum jest bardzo wszechstronna i wydajna w wielu przypadkach użycia –