Wie man den Typ überprüft, ist enum oder nicht in Typoskript
Ich habe einen String-Aufzählungstyp wie:
export enum UserRole {
admin = "admin",
active = "active",
blocked = "blocked"
}
Ich möchte überprüfen, ob eine bestimmte Zeichenfolge emule ist oder nicht.
const djson = JSON.parse(decode_string)
if(djson && (djson.role instanceof UserRole) // I just want to check the role is enum string or not. Obviously this way is wrong.
Wie es geht?
Antworten
Javascript hat nicht das Konzept von Enum, daher ist es nicht möglich. Beim Kompilieren übersetzt Typoskript die Enum-Definition in ein normales Javascript-Objekt, das Sie täglich verwenden. Sie können keine Informationen zu Enum einsehen.
Also diese Aufzählung Definition unten
enum UserRole {
admin = "admin",
active = "active",
blocked = "blocked"
}
Wird in so etwas übersetzt
var UserRole;
(function (UserRole) {
UserRole["admin"] = "admin";
UserRole["active"] = "active";
UserRole["blocked"] = "blocked";
})(UserRole || (UserRole = {}));
Normalerweise halte ich mich von enums fern, weil sie eine der wenigen TypeScript-Funktionen sind, die gegen die eigenen Designziele von TypeScript verstoßen : Sie sind nicht Teil von JavaScript, werden jedoch zu JavaScript kompiliert. Dies bedeutet, dass wir nicht einfach auf eine JavaScript-Spezifikation für die Laufzeit verweisen können.
Wie auch immer, es scheint, als ob Sie am Laufzeitverhalten von enums interessiert sind und nicht unbedingt am Typ des Systemverhaltens. Im Folgenden werde ich mich darum kümmern, Ihre Frage zur Laufzeit und nicht im Compiler zu beantworten. Zur Laufzeit ist ein enumnur ein Objekt mit Schlüsseln und Werten. Solange Sie eine Zeichenfolgenaufzählung verwenden , sind die Schlüssel und Werte mit den von Ihnen festgelegten Schlüsseln und Werten identisch.
(Wenn Sie eine numerische Aufzählung verwenden, gibt es auch umgekehrte Zuordnungen, bei denen der Wert als Schlüssel und der Schlüssel als Wert hinzugefügt wird. Dies ist besonders verwirrend, scheint aber nicht auf Ihre Frage zuzutreffen, also werde ich es tun Vermeiden Sie es, darüber zu sprechen, es sei denn, Sie werden für weitere Details gedrückt.)
Sie haben die Schlüssel und Werte von Ihnen so eingestellt enum, dass sie identisch sind, was zu einer Mehrdeutigkeit führt, die ich vermeiden möchte. Ich werde so neu definieren UserRole:
enum UserRole {
ADMIN = "admin",
ACTIVE = "active",
BLOCKED = "blocked",
}
Jetzt können wir den Unterschied zwischen der Frage "Ist diese Zeichenfolge ein Schlüssel der Aufzählung?" Und "Ist diese Zeichenfolge ein Wert der Aufzählung?" Zeigen. Angenommen, wir haben eine Zeichenfolge roleund möchten sehen, ob es sich um einen Schlüssel der Aufzählung handelt, können wir Folgendes tun:
const roleIsEnumKey = role in UserRole;
console.log("role " + role + (roleIsEnumKey ? " IS " : " IS NOT ") + "a key in UserRole");
Und wenn wir sehen wollen, ob es ein Wert der Aufzählung ist, können wir dies tun:
const roleIsEnumValue = (Object.values(UserRole) as string[]).includes(role);
console.log("role " + role + (roleIsEnumValue ? " IS " : " IS NOT ") + "a value in UserRole");
Angenommen, Sie verwenden eine Version von JS mit Object.values()und Array.prototype.includes(). Wenn nicht, können Sie über Object.keys()oder eine andere gewünschte Methode iterieren .
Mal sehen, ob es funktioniert:
check(JSON.stringify({ role: "ADMIN" }));
// role ADMIN IS a key in UserRole
// role ADMIN IS NOT a value in UserRole
check(JSON.stringify({ role: "admin" }));
// role admin IS NOT a key in UserRole
// role admin IS a value in UserRole
check(JSON.stringify({ role: "random" }));
// role random IS NOT a key in UserRole
// role random IS NOT a value in UserRole
Sieht gut aus. Der Punkt ist, zur Laufzeit enumist das nur ein Objekt, und Sie können seine Schlüssel und Werte so überprüfen, wie Sie es mit jedem Objekt tun würden.
Spielplatz Link
Wie @NearHuscarl sagte, gibt es keine Möglichkeit, dies zu überprüfen. Sie können jedoch überprüfen, ob djson.role (string)es sich um einen der folgenden UserRole (enum)Werte handelt:
!!(Object.values(UserRole).find(enumValue => enumValue === djson.role)));
Der Wert von a enumist entweder eine Zeichenfolge oder eine Zahl. Sie können also nur anhand einer Zeichenfolge oder Zahl testen.
Wir können beginnen, indem wir einen benutzerdefinierten Typschutz erstellen, der folgendermaßen aussehen würde:
function isInstance<T extends object>(value: string, type: T): type is T {
return Object.values(type).includes(value)
}
Dies gibt true oder false zurück, wenn der Wert in der Aufzählung gefunden wird (dies funktioniert nicht gut bei Zahlen oder Aufzählungen mit derselben Zeichenfolge).
enum Animal {
Cat = 'cat',
Dog = 'dog'
}
enum Plant {
Tree = 'tree',
Flower = 'flower'
}
function isInstance<T extends object>(value: string | number, type: T): type is T {
return Object.values(type).includes(value)
}
console.log(isInstance('dog', Animal)) // True
console.log(isInstance('dog', Plant)) // False