为什么 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 中,interface
s 没有发出。这意味着 Foo
和 Foo.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;
在这种情况下,x
和 y
具有相同的类型,但是如果您尝试对任何一个使用 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
}
这段代码是我写的
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 中,interface
s 没有发出。这意味着 Foo
和 Foo.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;
在这种情况下,x
和 y
具有相同的类型,但是如果您尝试对任何一个使用 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
}