Mengapa 'instanceof' di TypeScript memberi saya kesalahan "'Foo' hanya mengacu pada suatu jenis, tetapi digunakan sebagai nilai di sini."?


91

Saya menulis kode ini

interface Foo {
    abcdef: number;
}

let x: Foo | string;

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

Tapi TypeScript memberi saya kesalahan ini:

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

Mengapa ini terjadi? Saya pikir itu instanceofdapat memeriksa apakah nilai saya memiliki tipe tertentu, tetapi TypeScript tampaknya tidak seperti ini.


Lihat jawabannya di bawah @ 4castle. Jika tidak, Anda benar, saya akan membuatnya Foo | string.
Daniel Rosenwasser


Dan kemungkinan duplikat Periksa apakah variabel adalah jenis antarmuka tertentu dalam gabungan skrip skrip (saya tidak benar-benar ingin palu sendirian)
Cerbrus

@Jenny O'Reilly, itu pasti duplikat dari Kemungkinan duplikat!
marckassay

Jawaban:


100

Apa yang sedang terjadi

Masalahnya adalah itu instanceofadalah konstruksi dari JavaScript, dan dalam JavaScript, instanceofmengharapkan nilai untuk operan sisi kanan. Secara khusus, di x instanceof FooJavaScript akan melakukan pemeriksaan waktu proses untuk melihat apakah Foo.prototypeada di mana saja dalam rantai prototipe x.

Namun, dalam TypeScript, interfaces tidak memiliki emit . Itu berarti bahwa baik Fooatau Foo.prototypeada pada saat runtime, jadi kode ini pasti akan gagal.

TypeScript mencoba memberi tahu Anda bahwa ini tidak akan pernah berhasil. Foohanyalah sebuah tipe, itu bukanlah nilai sama sekali!

"Apa yang bisa saya lakukan sebagai gantinya instanceof?"

Anda dapat melihat pelindung tipe dan pelindung tipe yang ditentukan pengguna .

"Tapi bagaimana jika aku baru saja beralih dari a interface ke a class?"

Anda mungkin tergoda untuk beralih dari a interfaceke a class, tetapi Anda harus menyadari bahwa dalam sistem tipe struktural TypeScript (di mana hal-hal terutama berbasis bentuk ), Anda dapat menghasilkan objek apa pun yang memiliki bentuk yang sama dengan kelas yang diberikan:

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;

Dalam hal ini, Anda memiliki xdan yyang memiliki tipe yang sama, tetapi jika Anda mencoba menggunakan instanceofsalah satu, Anda akan mendapatkan hasil yang berlawanan di sisi lain. Jadi instanceoftidak akan benar-benar memberitahu Anda banyak tentang jenis jika Anda mengambil keuntungan dari jenis struktural dalam naskah.


2
Akan butuh waktu lama bagi saya untuk menemukan yang satu itu untuk diri saya sendiri!
Matthew Layton

Jadi pada dasarnya saya tidak mendapatkan ide dari jawaban mana yang lebih baik. Kelas? karena Anda mendetailnya. Tapi bingung saat Anda menyebutkan "Anda mungkin tergoda". Jadi bagaimana jika saya harus membandingkan semua properti dan bukan hanya properti renang seperti dalam dokumen untuk penjaga tipe?
HalfWebDev

5
Poin utama di sini adalah instanceofbekerja dengan kelas, bukan antarmuka. Pemikiran itu perlu ditekankan.
inorganik

5

Untuk melakukan pengecekan tipe saat runtime dengan sebuah antarmuka menggunakan pelindung tipe , jika antarmuka yang ingin Anda periksa memiliki properti / fungsi yang berbeda .

Contoh

let pet = getSmallPet();

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

Bagaimana jika saya belajar tentang bebek dan menambahkan fungsi swim () ke antarmuka Bird saya? Bukankah setiap hewan peliharaan diklasifikasikan sebagai ikan dalam tipe penjaga? Dan jika saya memiliki tiga antarmuka dengan tiga fungsi masing-masing dan dua tumpang tindih dengan salah satu antarmuka lainnya?
Kayz

1
@Kayz jika Anda tidak memiliki properti / fungsi yang secara unik mengidentifikasi antarmuka, Anda tidak dapat membedakannya. Hewan peliharaan Anda yang sebenarnya bisa menjadi Duck, Anda jenis penjaga itu menjadi Fish, tetapi masih ada pengecualian runtime saat Anda memanggil swim(). Sarankan Anda membuat 1 tingkat antarmuka umum (misalnya Swimmable) dan memindahkan swim()fungsi Anda ke sana, kemudian tipe penjaga masih terlihat bagus ((pet as Swimmable).swim.
Lee Chee Kiam

Untuk mencegah typecasting, Anda dapat menggunakan 'swim' in petkondisi. Ini akan mempersempit ke subset yang memiliki telah swimdidefinisikan (ex: Fish | Mammal)
Akxe

2

Daniel Rosenwasser mungkin benar dan keren, tetapi saya ingin mengubah jawabannya. Sangat mungkin untuk memeriksa contoh x, lihat cuplikan kode.

Tetapi sama mudahnya untuk menetapkan x = y. Sekarang x tidak akan menjadi turunan dari C karena y hanya berbentuk 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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.