TypeScript'teki 'instanceof' bana neden "'Foo' yalnızca bir türe işaret ediyor, ancak burada bir değer olarak kullanılıyor" hatası veriyor?


91

Bu kodu yazdım

interface Foo {
    abcdef: number;
}

let x: Foo | string;

if (x instanceof Foo) {
    // ...
}

Ama TypeScript bana şu hatayı verdi:

'Foo' only refers to a type, but is being used as a value here.

Bu neden oluyor? Bunun instanceof, değerimin belirli bir türe sahip olup olmadığını kontrol edebileceğini düşündüm , ancak TypeScript bundan hoşlanmıyor gibi görünüyor.


Aşağıdaki cevaba bakın @ 4castle. Aksi takdirde haklısın, başaracağım Foo | string.
Daniel Rosenwasser



@Jenny O'Reilly, şimdi bu kesinlikle Olası bir kopyasının bir kopyası!
marckassay

Yanıtlar:


100

Neler oluyor

Sorun, instanceofJavaScript'ten bir yapı olması ve JavaScript'te sağ taraftaki işlenen için instanceofbir değer beklemesidir . Özellikle x instanceof FooJavaScript Foo.prototype, prototip zincirinde herhangi bir yerde bulunup bulunmadığını görmek için bir çalışma zamanı kontrolü gerçekleştirecektir x.

Bununla birlikte, TypeScript'te interfaces yayma içermez. Bu , çalışma zamanında ne olmadığı Foove Foo.prototypevar olmadığı anlamına gelir , bu nedenle bu kod kesinlikle başarısız olacaktır.

TypeScript size bunun asla işe yaramayacağını söylemeye çalışıyor . Foosadece bir tür, hiç de bir değer değil!

"Bunun yerine ne yapabilirim instanceof?"

Tip korumalarına ve kullanıcı tanımlı tip korumalarına bakabilirsiniz .

"Ama ben sadece bir anahtarlamalı ne olur interface a class?"

Bir geçiş için cazip olabilir interfacea class, ancak typescript yapısal tip sisteminde ki (işler öncelikle nerede farkına varmalıdır tabanlı biçimden ), belirli bir sınıfla aynı şekle sahip herhangi bir nesneyi üretebilir:

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;

Bu durumda, sahip xve yaynı tür olduğunu, ancak kullanmayı deneyin eğer instanceofikisinden biri üzerinde, diğer ilgili ters bir sonuç elde edersiniz. Yani instanceofolmaz gerçekten sen daktilo yapısal tiplerinin yararlanarak eğer türü hakkında kadarını söyleyebilirim.


2
Bunu kendim için fark etmem yaşlarımı alırdı!
Matthew Layton

Yani temelde, daha iyi olan cevabın fikrini alamadım. Sınıf? çünkü detaylandırdın. Ama "baştan çıkarabilirsin" dediğin gibi kafan karıştı. Öyleyse, tip korumaları belgelerinde olduğu gibi sadece yüzme özelliğini değil, tüm özellikleri karşılaştırmam gerekirse ne olur?
HalfWebDev

7
Buradaki ana nokta instanceof, arayüzlerle değil, sınıflarla çalışmasıdır. Bunun vurgulanması gerektiğini düşündüm.
inorganik

5

Bir arabirimle çalışma zamanında tür denetimi yapmak için, denetlemek istediğiniz arabirimler farklı özelliklere / işlevlere sahipse, tür korumaları kullanmaktır .

Misal

let pet = getSmallPet();

if ((pet as Fish).swim) {
    (pet as Fish).swim();
} else if ((pet as Bird).fly) {
    (pet as Bird).fly();
}

Ördekler hakkında bir şeyler öğrenirsem ve Kuş arayüzüme swim () işlevini eklersem ne olur? Her evcil hayvan bir tür bekçide balık olarak sınıflandırılmaz mı? Ve eğer her biri üç işleve sahip üç arayüzüm varsa ve ikisi diğer arayüzlerden biriyle örtüşüyorsa?
Kayz

1
@Kayz, bir arayüzü benzersiz bir şekilde tanımlayan özelliklere / işlevlere sahip değilseniz, onları gerçekten ayırt edemezsiniz. Aslında bir evcil hayvanınız olabilir Duck, bekçi yazarsınız Fish, ancak çağırdığınızda hala çalışma zamanı istisnası yoktur swim(). 1 düzey ortak arabirim oluşturmanızı Swimmableve swim()işlevlerinizi oraya taşımanızı , ardından koruma yazın hala iyi görünmesini önerin ((pet as Swimmable).swim.
Lee Chee Kiam

Tipik dökümünü önlemek için 'swim' in petkoşulu kullanabilirsiniz . Bu etmiş olan bir alt kümesine daraltmak olacaktır swim: tanımlı (ex Fish | Mammal)
Akxe

2

Daniel Rosenwasser haklı ve züppe olabilir ama cevabında bir değişiklik yapmak istiyorum. X örneğini kontrol etmek tamamen mümkündür, kod parçacığına bakın.

Ancak x = y'yi atamak da aynı derecede kolaydır. Şimdi, y yalnızca C şeklinde olduğundan x, C'nin bir örneği olmayacaktı.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.