Napisałem ten kod
interface Foo {
abcdef: number;
}
let x: Foo | string;
if (x instanceof Foo) {
// ...
}
Ale TypeScript dał mi ten błąd:
'Foo' only refers to a type, but is being used as a value here.
Dlaczego to się dzieje? Pomyślałem, że instanceof
może to sprawdzić, czy moja wartość ma określony typ, ale wydaje się, że TypeScript tego nie lubi.
javascript
typescript
instanceof
Daniel Rosenwasser
źródło
źródło
Foo | string
.Odpowiedzi:
Co się dzieje
Problem polega na tym, że
instanceof
jest to konstrukcja z JavaScript, aw JavaScriptinstanceof
oczekuje wartości dla operandu po prawej stronie. W szczególności wx instanceof Foo
JavaScript przeprowadzi sprawdzenie w czasie wykonywania, aby sprawdzić, czyFoo.prototype
istnieje gdziekolwiek w łańcuchu prototypówx
.Jednak w TypeScript
interface
s nie emitują. Oznacza to, że aniFoo
nieFoo.prototype
istnieje w czasie wykonywania, więc ten kod na pewno zawiedzie.TypeScript próbuje ci powiedzieć, że to nigdy nie zadziała.
Foo
to tylko typ, to wcale nie jest wartość!„Co mogę zamiast tego zrobić
instanceof
?”Możesz zajrzeć do zabezpieczeń typów i zabezpieczeń typów zdefiniowanych przez użytkownika .
- A co, jeśli właśnie przełączyłem się z an
interface
na aclass
?Możesz pokusić się o przejście z a
interface
na aclass
, ale powinieneś zdać sobie sprawę, że w systemie typów strukturalnych TypeScript (gdzie rzeczy są głównie oparte na kształtach ), możesz utworzyć dowolny obiekt, który ma taki sam kształt jak dana klasa:class C { a: number = 10; b: boolean = true; c: string = "hello"; } let x = new C() let y = { a: 10, b: true, c: "hello", } // Works! x = y; y = x;
W tym przypadku masz
x
iy
mają ten sam typ, ale jeśli spróbujesz użyćinstanceof
jednego z nich, uzyskasz odwrotny wynik na drugim. Więcinstanceof
tak naprawdę nie powie ci zbyt wiele o typie, jeśli korzystasz z typów strukturalnych w TypeScript.źródło
instanceof
działa z klasami, a nie interfejsami. Pomyślałem, że należy to podkreślić.Aby sprawdzić typ w czasie wykonywania za pomocą interfejsu, należy użyć ochrony typów , jeśli interfejsy, które chcesz sprawdzić, mają różne właściwości / funkcje.
Przykład
let pet = getSmallPet(); if ((pet as Fish).swim) { (pet as Fish).swim(); } else if ((pet as Bird).fly) { (pet as Bird).fly(); }
źródło
Duck
strażnikiem, którym się stanieFish
, ale nadal nie ma wyjątku w czasie wykonywania, gdy wywołujeszswim()
. Zaproponuj utworzenie 1 poziomu wspólnego interfejsu (np.Swimmable
) I przeniesienieswim()
tam funkcji, a następnie wpisz guard nadal dobrze wygląda z((pet as Swimmable).swim
.'swim' in pet
warunku. Będzie to sprowadzić do podzbioru że musi miećswim
zdefiniowany (npFish | Mammal
)Daniel Rosenwasser może mieć rację i elegancko, ale mam ochotę zmienić jego odpowiedź. W pełni można sprawdzić wystąpienie x, zobacz fragment kodu.
Ale równie łatwo jest przypisać x = y. Teraz x nie byłby instancją C, ponieważ y miałby tylko kształt C.
class C { a: number = 10; b: boolean = true; c: string = "hello"; } let x = new C() let y = { a: 10, b: true, c: "hello", } console.log('x is C? ' + (x instanceof C)) // return true console.log('y is C? ' + (y instanceof C)) // return false
źródło
Sprawdź, czy plik ur jest odpowiedniego typu. Tagi nie są dozwolone w plikach js, ale są dozwolone w plikach jsx
źródło