【问题标题】:TypeScript instanceof not working打字稿实例不起作用
【发布时间】:2018-02-08 09:07:29
【问题描述】:

我在使用 instanceof 运算符时遇到问题,它似乎不起作用。这是我的代码的一部分:

        const results = _.map(items, function(item: Goal|Note|Task, index: number) { 
            let result = {};
            if (item instanceof Goal) {
                result = { id: index, title: item.name };
            } else if (item instanceof Note) {
                result = { id: index, title: item.content.text };
            } else if (item instanceof Task) {
                result = { id: index, title: item.name };
            }

            console.log(item);
            console.log(item instanceof Goal);
            console.log(item instanceof Note);
            console.log(item instanceof Task);

            return result; 
        });

我所有的日志都是假的,这是控制台的样子:

它们都不匹配,尽管明确表示只有 3 种类型是可能的。您还可以看到类型名称为 Goal 的对象本身,所以我不明白为什么它与 instanceof Goal 不匹配。

有什么想法吗?

【问题讨论】:

  • 你是如何生成items的?它们是通过构造函数创建的吗?如果不是,它们将不是给定类的实例。
  • 您是否复制了对象?通过 JSON.parse 或 Object.assign?
  • 它们是来自 API/http 调用的响应。一定是为什么他们的 typeofs 总是对象而不是特定类型?
  • @AnimaSola 对。要使instanceof 工作,您需要从构造函数中实际制作它们。否则,它们只是恰好与您想要的对象具有相同形状的对象。
  • 感谢@MikeC,选择使用 hasOwnProperty。

标签: javascript typescript types casting instanceof


【解决方案1】:

instanceof 仅当它与构造它的函数或类匹配时才会返回 true。这里的item 是一个普通的Object

const a = { a: 1 } // plain object
console.log(a);

// {a:1}                 <-- the constructor type is empty
//   a: 1
//   __proto__: Object   <-- inherited from

a instanceof A         // false because it is a plain object
a instanceof Object    // true because all object are inherited from Object

如果使用构造函数或类构造,那么 instanceof 将按预期工作:

function A(a) {
    this.a = a;
}

const a = new A(1);    // create new "instance of" A
console.log(a);

// A {a:1}               <-- the constructor type is `A`

a instanceof A         // true because it is constructed from A
a instanceof Object    // true

如果GoalInterface,它只会检查对象的结构而不是其类型。如果Goal 是一个构造函数,那么它应该为instanceof 检查返回true。

尝试类似:

// interface Goal {...}
class Goal {...}        // you will have to change the way it works.

items = [
   new Goal()
];

2021 年更新:

最近在玩 Typescript,想出了一个更好的解决方案,可以同时在 Typescript 和 JavaScript 中使用:

尝试类似:

interface Goal {
    getCount(): number;
}

class Goal implements Goal {
    getCount() {
        return 3;
    }
}

function getItemCount(item: Goal | Note | Task) {
    return item instanceof Goal ? item.getCount() : 'not a goal';
}

console.log(getItemCount(new Goal()));  // 3
console.log(getItemCount('goal'));      // 'not a goal';

这里的接口和类同名,所以它们可以同时用作类型和实例检查器。

更改接口Goal 签名或类Goal 签名会抛出类似:

TS2394: This overload signature is not compatible with its implementation signature.

【讨论】:

  • 可悲的是,我遇到了一个案例,其中 typeof 对使用构造函数创建的对象失败。记录它们将显示正确的类型,但检查仍然失败。
  • @mcv typeof 不会在 JavaScript 中为您提供类型,typeof 仅适用于原始类型,这意味着您将得到 Object 作为任何类型检查的结果。您可能想尝试比较obj.constructor。这里是 constructor referencetypeof reference
  • 它解释了它是如何工作的,当然。但它没有提供解决方案?
  • @GopikrishnaS 那是我的错字;我的意思是instanceof,而不是typeof。在我的情况下它失败的原因是项目中存在同名的不同类,并且不知何故将一个类导入该文件而不是我的意思。 (我已经将这两个不同但相似的数据模型重构为一个明确的模型。)
  • @CularBytes 答案是:使用构造函数,否则 instanceof 将不起作用。
【解决方案2】:

你也可以使用类型保护来发挥你的优势:

https://basarat.gitbooks.io/typescript/docs/types/typeGuard.html

https://www.typescriptlang.org/docs/handbook/advanced-types.html

例如,如果你对你的类使用文字类型保护:

class Goal {
 type: 'goal'
...
}

那么检查就这么简单:

if (item.type === 'goal') {
}

或者您可以编写自己的类型保护:

function isNote(arg: any): arg is Note {
    // because only your Note class has "content" property?
    return arg.content !== undefined;
}

if (isNote(item)) {
    result = { id: index, title: item.content.text };
}

【讨论】:

  • 从 API 加载对象时,您仍然需要设置 type。但这比其他人提供的解决方案要简单一些。
【解决方案3】:

尝试使用构造函数实例化对象。我也遇到了同样的情况,因为我出于测试目的手动模拟了对象。如果您像以下示例一样创建项目,它应该可以工作:

item: Goal = new Goal(*item values*)

【讨论】:

    【解决方案4】:

    正如@Gopikrishna 指出的那样,从JSON.parse 解析或从API 接收的对象将与您的自定义Class 不匹配,因为它不是通过所需类的new 运算符创建的。

    一种解决方法是首先将对象转换为所需的类,然后根据undefined 检查属性。

    class User{
    displayName:string;
    id:string;
    }
    
    const user = obj as User;
    if (user.displayName!==undefined) {
        //do your thing here
    }
    

    【讨论】:

      猜你喜欢
      • 2022-11-09
      • 2020-03-18
      • 1970-01-01
      • 2017-02-20
      • 2016-11-21
      • 2021-09-25
      • 1970-01-01
      • 2016-06-16
      • 2018-05-25
      相关资源
      最近更新 更多