为什么 TypeScript 中的 'instanceof' 会给我错误“'Foo' 只引用一个类型,但在这里被用作一个值。”?

Why does 'instanceof' in TypeScript give me the error "'Foo' only refers to a type, but is being used as a value here."?

这段代码是我写的

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 似乎不喜欢这样。

instanceof 使用 classes,而不是接口。

怎么回事

问题是 instanceof 是 JavaScript 的构造,而在 JavaScript 中,instanceof 需要一个 对于右侧操作数。 具体来说,在x instanceof Foo中JavaScript会进行一次运行时检查,看Foo.prototype是否存在于x.

的原型链中的任何地方

然而,在 TypeScript 中,interfaces 没有发出。这意味着 FooFoo.prototype 在运行时都不存在,所以这段代码肯定会失败。

TypeScript 试图告诉您这可能永远 行得通。 Foo 只是一个类型,根本不是一个值!

“除了 instanceof,我还能做什么?”

你可以看看type guards and user-defined type guards.

“但是如果我只是从 interface 切换到 class 呢?”

您可能想从 interface 切换到 class,但您应该意识到在 TypeScript 的结构类型系统中(其中主要是 基于形状的), 你可以生成任何与给定形状相同的对象 class:

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 不会 真正地 告诉您很多关于类型的信息。

Daniel Rosenwasser 可能是对的,花花公子,但我想对他的回答做一个修正。完全可以检查 x 的实例,请参阅代码片段。

但是给 x = y 赋值同样容易。现在 x 不会是 C 的实例,因为 y 只有 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

要在运行时使用接口进行类型检查,请使用 type guards,如果您要检查的接口具有 不同 properties/functions.

示例

let pet = getSmallPet();

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

当检查对象是否符合接口签名时,我认为合适的方法是考虑使用“类型谓词”: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates

您可以使用 the in operator narrowing 检查您需要的元素是否在对象中。

用这个方法,你可以验证x是字符串还是Foo

if ('abcdef' in x) {
    // x is instance of Foo
}