Skip to content

Bug when transpiling Promise class/constructor patch #15294

Description

This is a bug report. On tsc version 2.2.2

I have this TS code:

const PConstructor  = global.Promise;

const Promise = global.Promise = class PatchedPromise extends PConstructor {
  constructor(executor: Function) {
    if (process.domain) {
      executor = executor && process.domain.bind(executor);
    }
    super(executor); // call native Promise constructor
  }
};

const then = Promise.prototype.then;
Promise.prototype.then = function (fn1: Function, fn2: Function) {

  if (process.domain) {
    fn1 = fn1 && process.domain.bind(fn1);
    fn2 = fn2 && process.domain.bind(fn2);
  }

  return then.call(this, fn1, fn2);
};

const katch = Promise.prototype.catch;
Promise.prototype.catch = function (fn1: Function) {
  if (process.domain) {
    fn1 = fn1 && process.domain.bind(fn1);
  }
  return katch.call(this, fn1);
}; 

This transpiles to:

'use strict';
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();

var PConstructor = global.Promise;
var Promise = global.Promise = (function (_super) {
    __extends(PatchedPromise, _super);
    function PatchedPromise(executor) {
        var _this = this;
        if (process.domain) {
            executor = executor && process.domain.bind(executor);
        }
        _this = _super.call(this, executor) || this;
        return _this;
    }
    return PatchedPromise;
}(PConstructor));
var then = Promise.prototype.then;
Promise.prototype.then = function (fn1, fn2) {
    if (process.domain) {
        fn1 = fn1 && process.domain.bind(fn1);
        fn2 = fn2 && process.domain.bind(fn2);
    }
    return then.call(this, fn1, fn2);
};
var katch = Promise.prototype.catch;
Promise.prototype.catch = function (fn1) {
    if (process.domain) {
        fn1 = fn1 && process.domain.bind(fn1);
    }
    return katch.call(this, fn1);
};

however the transpiled code does not work, while the following vanilla JS / ES6 code works:

const PConstructor = global.Promise;

const Promise = global.Promise = class PatchedPromise extends PConstructor {
  constructor(executor) {
    if (process.domain) {
      executor = executor && process.domain.bind(executor);
    }
    super(executor); // call native Promise constructor
  }
};

const then = Promise.prototype.then;
Promise.prototype.then = function (fn1, fn2) {

  if (process.domain) {
    fn1 = fn1 && process.domain.bind(fn1);
    fn2 = fn2 && process.domain.bind(fn2);
  }

  return then.call(this, fn1, fn2);
};

const katch = Promise.prototype.catch;
Promise.prototype.catch = function (fn1) {
  if (process.domain) {
    fn1 = fn1 && process.domain.bind(fn1);
  }
  return katch.call(this, fn1);
};

Here is the test:

const patch = require('../../../lib/patches/all');   // load the patch

process.on('uncaughtException', function(err){
  console.log(' This is uncaught => ', err);
});

const domain = require('domain');
const d = domain.create();

d.on('error', function(err){
  console.error(' => Domain caught => ',err);
});

d.run(function(){
      Promise.resolve().then(function(){
        process.nextTick(function(){
            throw new Error('rah'); // <<<<<<<< the domain will catch this
        });
     });
});

if we load the plain vanilla JS patch, this test script works as expected.

However, if we load the patch generated by TypeScript, we get this error:

TypeError: #<PatchedPromise> is not a promise

Pretty intense, by I am very certain this is some sort of bug.

Activity

  1. RyanCavanaugh commented on Apr 20, 2017

    @RyanCavanaugh
    Member
  2. mhegazy commented on Apr 26, 2017

    @mhegazy
    Contributor

    This is not the same as other ES5-builtins. this is a duplicate of #15202.

    The main issue here is that ES6 classes (e.g. Promise) are not callable, the way ES5 built in classes (e.g. Array). The emitted code that the compiler produces uses super.call which throws in ES6 engine.

  3. locked and limited conversation to collaborators on Jun 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions