代码之家  ›  专栏  ›  技术社区  ›  Daniel Rosenwasser

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

  •  166
  • Daniel Rosenwasser  · 技术社区  · 7 年前

    我写了这个代码

    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

    5 回复  |  直到 7 年前
        1
  •  163
  •   Daniel Rosenwasser    2 年前

    TL;博士

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


    TypeScript想告诉我什么?

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

    然而,在TypeScript中, interface s没有发射。这同样适用于 type 别名。这意味着两者都不是 Foo 也没有 傅。原型 存在于运行时,因此此代码肯定会失败。

    从不 工作 只是一个类型,它根本不是一个值!

    如果你来自另一种语言,你可能打算在这里使用一个类。课程 在运行时创建值,但下面有一些注释,您可能需要阅读。

    运算符 如果我还想要一个 界面 ?"

    你可以调查 type guards and user-defined type guards .

    “但如果我只是从一个 界面 到a class ?"

    你可能会想从 界面 到a ,但您应该意识到,在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 类型相同,但如果您尝试使用 运算符 在任何一种情况下,在另一种情况下都会得到相反的结果。所以 运算符 不会 真正地 如果您正在利用TypeScript中的结构类型,请详细介绍该类型。

        2
  •  14
  •   Lee Chee Kiam Kevin    4 年前

    要在运行时使用接口进行类型检查,请使用 type guards ,如果要检查的接口具有 不同的 属性/功能。

    实例

    let pet = getSmallPet();
    
    if ((pet as Fish).swim) {
        (pet as Fish).swim();
    } else if ((pet as Bird).fly) {
        (pet as Bird).fly();
    }
    
        3
  •  3
  •   Elias Vesterlund    5 年前

    丹尼尔·罗森瓦瑟(DanielRosenwasser)可能是对的,但我想修改一下他的答案。完全可以检查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
    
        4
  •  1
  •   Janos    3 年前

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

        5
  •  1
  •   Giuseppedes    3 年前

    您可以使用 the in operator narrowing 用于检查所需元素是否在对象中。

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

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