打字稿实例不起作用

Posted

技术标签:

【中文标题】打字稿实例不起作用【英文标题】: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。 【参考方案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 reference 和 typeof 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

【讨论】:

以上是关于打字稿实例不起作用的主要内容,如果未能解决你的问题,请参考以下文章

打字稿'可选'(可为空)'?语法不起作用(部分)

打字稿RefForwardingComponent不起作用

打字稿异步/等待不起作用

打字稿重载箭头功能不起作用

打字稿计算的吸气剂不起作用

打字稿导入模块作为变量不起作用