instance[output.propName].subscribe is not a function resulting from polyfill

时间:2018-02-03 11:25:58

标签: angular typescript karma-jasmine

I'm running into a strange issue. I've researched the error, and it generally seems to be related to the use of @Output or EventEmitter, but that's not the case here.

I get the following error in my application if I have a particular polyfill in place:

TypeError: instance[output.propName].subscribe is not a function
    at createDirectiveInstance (http://localhost:9876/_karma_webpack_/webpack:/Users/stuart/localhost/projects/tt-new/work-group/node_modules/@angular/core/esm5/core.js:12319:71)
    at createViewNodes (http://localhost:9876/_karma_webpack_/webpack:/Users/stuart/localhost/projects/tt-new/work-group/node_modules/@angular/core/esm5/core.js:13776:38)
    at callViewAction (http://localhost:9876/_karma_webpack_/webpack:/Users/stuart/localhost/projects/tt-new/work-group/node_modules/@angular/core/esm5/core.js:14210:1)
    at execComponentViewsAction (http://localhost:9876/_karma_webpack_/webpack:/Users/stuart/localhost/projects/tt-new/work-group/node_modules/@angular/core/esm5/core.js:14119:1)
    at createViewNodes (http://localhost:9876/_karma_webpack_/webpack:/Users/stuart/localhost/projects/tt-new/work-group/node_modules/@angular/core/esm5/core.js:13804:1)
    at createRootView (http://localhost:9876/_karma_webpack_/webpack:/Users/stuart/localhost/projects/tt-new/work-group/node_modules/@angular/core/esm5/core.js:13665:1)
    at callWithDebugContext (http://localhost:9876/_karma_webpack_/webpack:/Users/stuart/localhost/projects/tt-new/work-group/node_modules/@angular/core/esm5/core.js:15090:26)
    at Object.debugCreateRootView [as createRootView] (http://localhost:9876/_karma_webpack_/webpack:/Users/stuart/localhost/projects/tt-new/work-group/node_modules/@angular/core/esm5/core.js:14373:1)
    at ComponentFactory_.webpackJsonp.../../../core/esm5/core.js.ComponentFactory_.create (http://localhost:9876/_karma_webpack_/webpack:/Users/stuart/localhost/projects/tt-new/work-group/node_modules/@angular/core/esm5/core.js:11260:26)
    at initComponent (http://localhost:9876/_karma_webpack_/webpack:/Users/stuart/localhost/projects/tt-new/work-group/node_modules/@angular/core/esm5/testing.js:1137:1)

The polyfill is as follows:

Object.prototype.clone = function(deep = false) {
    return (deep)
        ? JSON.parse(JSON.stringify(this)) // Deep clone - copies object property values in full.
        : Object.assign({}, this);         // Shallow clone - copies property values (including object references rather than object).
};

Can anyone help me understand why this might cause an error inside createDirectiveInstance? If I comment this code out, the error goes away. It's not simply having a polyfill that causes problems - there's another, which adds Array.prototype.upsert, which doesn't cause problems.

4 个答案:

答案 0 :(得分:99)

我刚刚遇到这个问题并检查了我编写的代码,我发现它是由于EventEmitter类导入错误(由visual studio代码的自动导入完成)引起的。

您只需要更改

import { EventEmitter } from 'events';

import { EventEmitter } from '@angular/core';

关于错误说明。 Angular将事件映射为可观察对象,因此它必须订阅子组件'事件并将它们发送给适当的组件。

寻找原始包我在https://github.com/Gozala/events/blob/master/events.js

找到了它的源代码

它只是失败了,因为你创建的EventEmitter中没有方法.suscribe()

答案 1 :(得分:0)

首先,实现未优化的克隆函数可能是一个坏主意,特别是当许多库已经实现它时[1]。话虽如此,如果您无法添加库,或者像我这样希望扩展Object的其他人,这个答案可能会有用。

这似乎是在Object.prototype上不正确地声明属性的结果。我猜测createDirectiveInstance列举Object.clone时有一些未满足的期望(它可能不应该枚举它)。相反,请使用Object.defineProperty方法:

Object.defineProperty(
  Object.prototype,
  'clone',
  {
    value: function (deep = false) {
      return (deep)
        ? JSON.parse(JSON.stringify(this)) // Deep clone - copies object property values in full.
        : Object.assign({}, this);         // Shallow clone - copies property values (including object references rather than object).
    },
    writable: false,
    enumerable: false
  }
);

可以重构为以下的Typescript:

function CloneThis(deep = false): any {
  return (deep)
    ? JSON.parse(JSON.stringify(this)) // Deep clone - copies object property values in full.
    : Object.assign({}, this);         // Shallow clone - copies property values (including object references rather than object).
}
Object.defineProperty(Object.prototype, 'clone',
  <PropertyDescriptor>{
    value: CloneThis,
    writable: false,
    enumerable: false
  }
);

但是,要从TypeScript获取类型推断,我认为您还需要声明Object的全局接口的扩展:

declare global {
  interface Object {
    clone(deep?: boolean): any;
  }
}

有关Object.defineProperty的更多资源,请参阅:

[1] Javascript克隆实现:

答案 2 :(得分:0)

我有同样的问题,我找到了一个适合我的解决方案。

在项目的node_modules / @ angular / core / @ angular / core.es5.js

10768: var /** @type {?} */ subscription = instance[((output.propName))].subscribe(...

不知怎的,它被propName称为assign,而instance对象上没有 if (instance[((output.propName))] && typeof instance[((output.propName))].subscribe === 'function'){ var /** @type {?} */ subscription = instance[((output.propName))].subscribe(eventHandlerClosure(view, /** @type {?} */ ((def.parent)).index, output.eventName)); /** @type {?} */ ((view.disposables))[def.outputIndex + i] = subscription.unsubscribe.bind(subscription); } 。只需put和if语句并确保它在调用之前有一个订阅函数。像这样的东西:

12515: view.disposables[i]();

您可能还需要在此处进行检查:

if (view.disposables[i] && typeof view.disposables[i] === 'function'){
          view.disposables[i]();
}
我这样做了:

lists=lists.stream()
           .sorted(Comparator.comparing(ObjModel::getModifiedtime).reversed())
           .collect(Collectors.toList());

我不推荐这个猴子补丁,但它对我有用,到目前为止我没有任何错误。我希望它有助于甚至帮助某人找到更好的解决方案。

答案 3 :(得分:-2)

我发现您不小心使用装饰了@Output的方法而不是属性,可能会遇到此错误。

例如,如果您拥有:

  <app-thing (onReady)="...">
  </app-thing>

确保在子组件中具有:

  @Output() onReady: Observable<...>

或:

  @Output() get onReady(): Observable<...> {
    ...
  }

...否:

  @Output() onReady(): Observable<...> {
    ...
  }