diff --git a/packages/zone.js/lib/common/promise.ts b/packages/zone.js/lib/common/promise.ts index 8f35e225b592a..44fb652c5823c 100644 --- a/packages/zone.js/lib/common/promise.ts +++ b/packages/zone.js/lib/common/promise.ts @@ -256,6 +256,8 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr const ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }'; + const noop = function() {}; + class ZoneAwarePromise implements Promise { static toString() { return ZONE_AWARE_PROMISE_TO_STRING; } @@ -374,12 +376,17 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr get[Symbol.toStringTag]() { return 'Promise' as any; } + get[Symbol.species]() { return ZoneAwarePromise; } + then( onFulfilled?: ((value: R) => TResult1 | PromiseLike)|undefined|null, onRejected?: ((reason: any) => TResult2 | PromiseLike)|undefined| null): Promise { - const chainPromise: Promise = - new (this.constructor as typeof ZoneAwarePromise)(null as any); + let C = (this.constructor as any)[Symbol.species]; + if (!C || typeof C !== 'function') { + C = ZoneAwarePromise; + } + const chainPromise: Promise = new (C as typeof ZoneAwarePromise)(noop); const zone = Zone.current; if ((this as any)[symbolState] == UNRESOLVED) { ((this as any)[symbolValue]).push(zone, chainPromise, onFulfilled, onRejected); @@ -395,8 +402,11 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr } finally(onFinally?: () => U | PromiseLike): Promise { - const chainPromise: Promise = - new (this.constructor as typeof ZoneAwarePromise)(null as any); + let C = (this.constructor as any)[Symbol.species]; + if (!C || typeof C !== 'function') { + C = ZoneAwarePromise; + } + const chainPromise: Promise = new (C as typeof ZoneAwarePromise)(noop); (chainPromise as any)[symbolFinally] = symbolFinally; const zone = Zone.current; if ((this as any)[symbolState] == UNRESOLVED) { diff --git a/packages/zone.js/test/common/Promise.spec.ts b/packages/zone.js/test/common/Promise.spec.ts index 42707b3ed7091..f5038b83f0818 100644 --- a/packages/zone.js/test/common/Promise.spec.ts +++ b/packages/zone.js/test/common/Promise.spec.ts @@ -103,11 +103,21 @@ describe( }).toThrowError('Must be an instanceof Promise.'); }); - xit('should allow subclassing', () => { + it('should allow subclassing with Promise.specices', () => { class MyPromise extends Promise { constructor(fn: any) { super(fn); } + + static get[Symbol.species]() { return MyPromise; } } - expect(new MyPromise(null).then(() => null) instanceof MyPromise).toBe(true); + expect(new MyPromise(() => {}).then(() => null) instanceof MyPromise).toBe(true); + }); + + it('Promise.specices should return ZoneAwarePromise', () => { + const empty = function() {}; + const promise = Promise.resolve(1); + const FakePromise = ((promise.constructor = {} as any) as any)[Symbol.species] = function( + exec: any) { exec(empty, empty); }; + expect(promise.then(empty) instanceof FakePromise).toBe(true); }); it('should intercept scheduling of resolution and then', (done) => {