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

mbyulnm0  于 2023-02-25  发布在  TypeScript
关注(0)|答案(6)|浏览(266)

我写了这段代码

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

vaqhlq81

vaqhlq811#

靶区; DR

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

TypeScript想告诉我什么?

问题在于instanceof是JavaScript的一个构造,在JavaScript中,instanceof的右边操作数需要一个 * value *,具体来说,在x instanceof Foo中,JavaScript将执行运行时检查,以查看Foo.prototype是否存在于x的原型链中的任何位置。
但是,在TypeScript中,interface没有emit,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不会"真正"告诉您关于类型的很多信息。

oyxsuwqo

oyxsuwqo2#

如果您希望检查的接口具有不同的属性/函数,则在运行时对接口执行类型检查是使用类型保护。
示例

let pet = getSmallPet();

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

v6ylcynt3#

丹尼尔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
s4n0splo

s4n0splo4#

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

5f0d552i

5f0d552i5#

您可以使用in运算符缩小范围来检查所需的元素是否在对象中。
使用此方法,可以验证x是字符串还是Foo

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

xriantvc6#

instanceof通常是正确答案。
然而,在我的例子中,我使用的是一个基元类型,instanceof Numberinstanceof number在ts编译器中都出错了:

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}

相关问题