web-dev-qa-db-fra.com

instance [output.propName] .subscribe n'est pas une fonction résultant de polyfill

Je rencontre un problème étrange. J'ai recherché l'erreur, et cela semble généralement être lié à l'utilisation de @Output ou EventEmitter, mais ce n'est pas le cas ici. 

J'obtiens l'erreur suivante dans mon application si un polyfill particulier est en 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)

Le polyfill est comme suit: 

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).
};

Quelqu'un peut-il m'aider à comprendre pourquoi cela pourrait causer une erreur dans createDirectiveInstance? Si je commente ce code, l'erreur disparaît. Ce n'est pas simplement le fait d'avoir un polyfill qui pose problème, il y en a un autre qui ajoute Array.prototype.upsert, ce qui ne pose pas de problème. 

17
Stuart Updegrave

Je viens de faire face à ce problème et en vérifiant le code que j'ai écrit, j'ai découvert qu'il était dû à une mauvaise importation de la classe EventEmitter (effectuée par l'importation automatique du code Visual Studio).

Vous avez juste besoin de changer 

import { EventEmitter } from 'events';

À

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

Et à propos de l'explication de l'erreur. Angular mappe les événements en tant qu'observables. Il doit donc s'abonner aux événements des composants enfants et les envoyer aux composants appropriés.

À la recherche du paquet original, j'ai trouvé son code source sur: https://github.com/Gozala/events/blob/master/events.js

Et cela échoue simplement car il n'y a pas de méthode .suscribe() dans EventEmitter que vous avez créé.

94
Adrian Abreu

J'ai eu le même problème et j'ai trouvé une solution qui a fonctionné pour moi. 

dans les noeuds_modules/@ angular/core/@ angular/core.es5.js du projet

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

D'une manière ou d'une autre, il obtenait une propName appelée assign qui ne figure pas dans l'objet instance. Il suffit de mettre et si déclaration et assurez-vous qu’il dispose d’une fonction d’abonnement avant de l’appeler. Quelque chose comme ça:

 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);
        }

Et vous devrez peut-être aussi vérifier ici:

12515: view.disposables[i]();

j'ai fait ça:

if (view.disposables[i] && typeof view.disposables[i] === 'function'){
          view.disposables[i]();
}

Je ne recommanderais pas ce patch de singe, mais cela a fonctionné pour moi et je n’ai pas eu d’erreur depuis. J'espère que cela aide ou même aide quelqu'un à trouver une meilleure solution.

0
marshy101

Tout d’abord, c’est probablement une mauvaise idée d’implémenter une fonction de clonage non optimisée, surtout lorsque de nombreuses bibliothèques l’ont déjà implémentée [1]. Cela dit, cette réponse peut être utile si vous ne pouvez pas ajouter de bibliothèques ou à d'autres personnes comme moi qui souhaitent étendre la variable Object.

Cela semble résulter d'une déclaration incorrecte d'une propriété sur Object.prototype. Je suppose que createDirectiveInstance a certaines attentes non satisfaites quand il énumère Object.clone (il ne devrait probablement pas être énuméré). Utilisez plutôt la méthode 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
  }
);

Cela pourrait être refactored au TypeScript suivant:

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
  }
);

Cependant, pour obtenir une inférence de type à partir de TypeScript, je pense que vous devez également déclarer une extension à l'interface globale pour Object:

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

Pour plus de ressources sur Object.defineProperty, voir:

[1] Implémentations Javascript Clone:

0
Anonymous