Javascript 为什么';instanceof';在TypeScript中,给我一个错误"';Foo';仅引用类型,但在此处用作值;?
我写了这段代码Javascript 为什么';instanceof';在TypeScript中,给我一个错误"';Foo';仅引用类型,但在此处用作值;?,javascript,typescript,instanceof,Javascript,Typescript,Instanceof,我写了这段代码 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似乎不喜欢这样。i
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
与类而不是接口一起工作
发生什么事?
问题在于,这是一个来自JavaScript的构造,在JavaScript中,instanceof
需要右侧操作数的值。
具体来说,在x实例中,Foo
JavaScript将执行运行时检查,以查看Foo.prototype
是否存在于x
的原型链中的任何位置
但是,在TypeScript中,接口
s没有发出。这意味着运行时既不存在Foo
也不存在Foo.prototype
,因此此代码肯定会失败
TypeScript试图告诉你这是不可能的Foo
只是一种类型,它根本不是一个值
“我能做什么来代替的实例?”
你可以调查一下
“但是如果我只是从接口
切换到类
,会怎么样?”
您可能会尝试从接口
切换到类
,但您应该意识到,在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;
在本例中,您有相同类型的x
和y
,但如果您尝试在其中一个上使用instanceof
,则在另一个上会得到相反的结果。因此,如果你利用TypeScript中的结构类型,那么,instanceof
不会真正告诉你很多关于类型的信息。丹尼尔·罗森瓦瑟可能是对的,但我想对他的答案做一个修改。完全可以检查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
如果要检查的接口具有不同的属性/函数,则在运行时使用正在使用的接口执行类型检查
范例
let pet = getSmallPet();
if ((pet as Fish).swim) {
(pet as Fish).swim();
} else if ((pet as Bird).fly) {
(pet as Bird).fly();
}
当检查对象是否符合接口签名时,我认为适当的方法是考虑使用“类型谓词”:
请参见下面@4castle的答案。否则,你是对的,我会把它做成Foo | string
。可能的重复和可能的重复(我真的不想单枪匹马地敲打它)@Jenny O'Reilly,现在这绝对是可能的重复!我花了好长时间才发现那个!所以基本上,我没有从答案中得到更好的答案。上课?因为你很详细。但在你提到“你可能被诱惑”的同时,我感到困惑。那么,如果我必须比较所有属性,而不是像文档中那样比较类型卫士的swim属性呢?这里的要点是instanceof
与类而不是接口一起工作。我想这需要强调一下。如果我了解鸭子并将函数swim()添加到我的鸟界面中,会怎么样?难道不是每一只宠物都会被归类为一类守卫中的鱼吗?如果我有三个接口,每个接口有三个函数,两个接口与另一个接口重叠?@Kayz如果没有唯一标识接口的属性/函数,就无法真正区分它们。您的宠物实际上可能是一只鸭子
,您键入guard,它将变成鱼
,但在调用swim()
时仍然没有运行时异常。建议您创建1级通用界面(例如,Swimmable
)并将您的swim()
函数移动到那里,然后键入guard仍然可以使用((宠物作为Swimmable).swim
。为了防止类型转换,您可以在pet
条件下使用'swim'。它会将其缩小到必须定义swim
的子集(例如:鱼|哺乳动物
)