为什么TypeScript中的"instanceof"会给我错误"'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似乎不喜欢这样。

TL;DR

instanceof使用类,而不是接口或类型别名。


TypeScript想告诉我什么

问题是instanceof是一个来自JavaScript的构造,而在JavaScript中,instanceof需要右侧操作数的。具体来说,在x instanceof Foo中,JavaScript将执行运行时检查,以查看Foo.prototype是否存在于x的原型链中的任何位置。

但是,在TypeScript中,interface没有发射。type别名也是如此。这意味着FooFoo.prototype在运行时都不存在,所以这段代码肯定会失败。

TypeScript正试图告诉您,这可能永远不会工作。Foo只是一个类型,根本不是一个值!

如果你来自另一种语言,你可能打算在这里使用一个类。类确实在运行时创建值,但您可能想在下面阅读一些关于这方面的注意事项。

"如果我仍然想要typeinterface,我可以做什么来代替instanceof">

您可以查看类型保护和用户定义的类型保护。

"但如果我只是从interface切换到class呢">

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

class C {
a: number = 10;
b: boolean = true;
c: string = "hello";
}
let x = new C()
let y: C = {
a: 10, b: true, c: "hello",
}
// Works!
x = y;
y = x;

在这种情况下,xy具有相同的类型,但如果在其中一个上尝试使用instanceof,则在另一个上会得到相反的结果。因此,如果您正在利用TypeScript中的结构类型,instanceof不会真正告诉您有关类型的信息。

要在运行时使用接口进行类型检查,如果要检查的接口具有不同的属性/函数,则使用类型保护。

示例

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

Daniel Rosenwaser可能是对的,但我想修改一下他的答案。完全可以检查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

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

您可以使用in运算符窄化来检查您需要的元素是否在对象中。

使用此方法,您可以验证x是字符串还是Foo

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

instanceof通常是正确答案。

然而,在我的案例中,我使用的是一个基元类型,并且ts编译器中的instanceof Numberinstanceof number都出错了:

TS2322: Type 'Number' is not assignable to type 'number'.
TS2693: 'number' only refers to a type, but is being used as a value here.

当使用基元类型时,typeof是正确答案:

if (typeof value === 'number') {this.propertyValue = value}

相关内容

最新更新