Typescript: Hur lägger man till typvakter för enums i unionstyper?
Följande kod ger fel:
- Vänstersidan av ett 'instanceof'-uttryck måste vara av typen 'any', ett objekt eller en typparameter.
- Typen 'E | C' kan inte tilldelas typen 'E'. Typen 'C' kan inte tilldelas typen 'E'.
enum E { FIRST = 1, SECOND = 2 };
class C {
value: E;
constructor(arg: C | E) {
if (arg instanceof C) { // 1.
this.value = arg.value;
} else {
this.value = arg; // 2.
}
}
}
var a: C = new C(E.SECOND);
console.log('a.value = ' + a.value);
var b: C = new C(a);
console.log('b.value = ' + b.value);
Trots felen verkar koden kompileras bra på TypeScript Playground och gör det som förväntas.
Svar #1
Två problem.
Det finns en bugg i kompilatorn där instanceof inte är tillåtet på unionstyper när en av dess beståndsdelar inte är en objekttyp. Detta håller på att åtgärdas (https://github.com/Microsoft/TypeScript/issues/2775)
Den andra saken är att instanceof inte orsakar avsmalning i else-blocket (https://github.com/Microsoft/TypeScript/issues/1719) eftersom ett misslyckat instanceof-kontroll inte nödvändigtvis betyder att objektet inte matchar det angivna gränssnittet. Detta är för närvarande "avsiktligt" men jag uppmuntrar dig att lämna en kommentar om att du tycker att detta beteende är överraskande eller oönskat (det tycker jag definitivt).
Svar #2
Ryan är förstås både vältalig och noggrann, men jag kan erbjuda dig en tillfällig lösning som du kan tycka är användbar. Trots dess möjliga användning, vänligen acceptera inte detta som svaret eftersom en långsiktig lösning på problemen relaterade till typkontroller kommer att vara bättre.
class C {
value: E;
constructor(arg: C | number) {
if(typeof arg === 'number') {
this.value = arg;
} else {
this.value = arg.value;
}
}
}
Denna ganska osmakliga lösning lutar sig på det faktum att enums och nummer trivs tillsammans. Du drar också nytta av bieffekten av typeof-kontroller som begränsar else-satsen.
