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


91

我写了这段代码

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


并且可能会重复检查变量是否是打字稿联合中的特定接口类型(我真的不想单枪匹马地敲它)
Cerbrus

@Jenny O'Reilly,现在绝对是可能重复的重复!
marckassay

Answers:


100

这是怎么回事

问题是这instanceof是JavaScript的构造,在JavaScript中,instanceof期望右侧操作数的值为。具体来说,在x instanceof FooJavaScript中将执行运行时检查,以查看Foo.prototype的原型链中是否存在x

但是,在TypeScript中,interfaces没有发出。这意味着在运行时既不存在Foo也不Foo.prototype存在,因此该代码肯定会失败。

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

“我该怎么办instanceof呢?”

您可以研究类型保护和用户定义的类型保护

“但是,如果我只是从interface a切换到aclass呢?”

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

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在任何一个上使用,您将在另一个上得到相反的结果。所以,instanceof不会真的能告诉你很多,如果你在服用打字稿结构类型的优势类型。


2
本来需要我花很长时间才能自己找到那个!
马修·雷顿

所以基本上我没有从答案中得到更好的主意。类?因为你详细了。但是,在您提到“您可能被诱惑”的同时感到困惑。那么,如果我必须比较所有属性,而不仅仅是像类型防护文档中的swim属性那样比较呢?
HalfWebDev

5
这里的重点是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();
}

如果我了解鸭子,并将函数swim()添加到Bird接口,该怎么办?难道每个宠物都不会被归类为鱼吗?如果我有三个接口,每个接口具有三个功能,并且两个接口与其他接口之一重叠?
凯兹

1
@Kayz如果您没有唯一标识接口的属性/功能,则无法真正区分它们。您的宠物实际上可能是a Duck,您键入guard成为宠物Fish,但调用时仍然没有运行时异常swim()。建议您创建1级通用接口(例如Swimmable)并将swim()功能移到那里,然后使用键入guard仍然看起来不错((pet as Swimmable).swim
Lee Chee Kiam

为了防止类型转换,您可以使用'swim' in pet条件。这将范围缩小到必须有一个子集swim:定义(前Fish | Mammal
Akxe

2

丹尼尔·罗森瓦瑟(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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.