TypeScriptの「instanceof」で「「Foo」は型のみを参照しているが、ここでは値として使用されている」というエラーが表示されるのはなぜですか?


93

私はこのコードを書きました

interface Foo {
    abcdef: number;
}

let x: Foo | string;

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

しかし、TypeScriptは私にこのエラーを与えました:

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

なんでこんなことが起こっているの?instanceof私の値が特定のタイプを持っているかどうかをチェックできると思いましたが、TypeScriptはこれを好まないようです。


@ 4castleの下の答えを参照してください。そうでなければ、あなたは正しいです、私はそれを作りますFoo | string
Daniel Rosenwasser 2017年



@Jenny O'Reilly、これは間違いなく重複の可能性のある重複です!
marckassay 2018

回答:


105

どうしたの

問題は、instanceofJavaScriptからの構成であり、JavaScriptでは、右側のオペランドのinstanceof予期していることです。具体的には、x instanceof FooJavaScriptでランタイムチェックを実行Foo.prototypeして、のプロトタイプチェーンのどこかに存在するかどうかを確認しますx

ただし、TypeScriptでは、interfacesにはemitがありません。つまり、実行時にFooFoo.prototype存在もしないため、このコードは間違いなく失敗します。

TypeScriptは、これが機能しないことを伝えようとしています。Foo単なるタイプであり、値ではありません。

「代わりに何ができinstanceofますか?」

タイプガードとユーザー定義のタイプガードを調べることができます。

「しかし、私がちょうどからに切り替えた場合interfaceclassどうなりますか?」

あなたはからスイッチに誘惑されるかもしれないinterfaceclass、しかし、あなたは(物事が主にされている活字体の構造型のシステムであることを認識すべきベース形状)、指定したクラスと同じ形状をしている任意のオブジェクトを生成することができます:

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;

この場合は、あなたが持っているxy同じ型を持つことができますが、使用してみた場合にinstanceofいずれか一方に、あなたは他の反対の結果を得るでしょう。したがって、TypeScriptで構造型を利用している場合は、型についてあまり説明しinstanceofませ


2
自分でそれを見つけるのに何年もかかったでしょう!
マシューレイトン

だから基本的に私は答えからアイデアを得ることができませんでした。クラス?あなたがそれを詳述したので。しかし、あなたが「あなたはたぶん誘惑された」と言ったのと同時に混乱しました。では、タイプガードのドキュメントのように水泳プロパティだけでなく、すべてのプロパティを比較する必要がある場合はどうなりますか?
HalfWebDev

8
ここでの主なポイントは、instanceofインターフェイスではなくクラスで機能することです。それを強調する必要があると思った。
inorganik

5

実行時にインターフェイスを使用して型チェックを行うには、タイプガードを使用します。チェックするインターフェイスに、異なるプロパティ/機能がある場合。

let pet = getSmallPet();

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

アヒルについて学び、Birdインターフェースに関数swim()を追加するとどうなりますか?すべてのペットはタイプガードの魚として分類されませんか?そして、それぞれ3つの機能を持つ3つのインターフェイスがあり、2つが他のインターフェイスの1つとオーバーラップしている場合はどうなりますか?
Kayz

1
@Kayzインターフェースを一意に識別するプロパティ/関数がない場合、それらを実際に区別することはできません。実際にはペットである可能性がありDuck、ガードと入力するとなりFishますが、を呼び出すとランタイム例外は発生しませんswim()。1レベルの共通インターフェース(例Swimmable)を作成しswim()、そこに関数を移動することをお勧めします((pet as Swimmable).swim。それでも、タイプガードはでうまく見えます。
Lee CheeKiam20年

型キャストを防ぐために、'swim' in pet条件を使用できます。swim定義する必要のあるサブセットに絞り込みます(例:Fish | Mammal
Akxe 2010年

2

ダニエル・ローゼンワッサーは正しくてダンディかもしれませんが、私は彼の答えを修正したいと思っています。xのインスタンスをチェックすることは完全に可能です。コードスニペットを参照してください。

しかし、x = yを割り当てるのも同様に簡単です。yはCの形状しかないため、xは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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.