Skip to content

Commit

Permalink
fix(zone.js): read Symbol.species safely
Browse files Browse the repository at this point in the history
We must read `Symbol.species` safely because `this` may be anything. For instance, `this`
may be an object without a prototype (created through `Object.create(null)`); thus
`this.constructor` will be undefined. One of the use cases is SystemJS creating
prototype-less objects (modules) via `Object.create(null)`. The SystemJS creates an empty
object and copies promise properties into that object (within the `getOrCreateLoad`
function). The zone.js then checks if the resolved value has the `then` method and invokes
it with the `value` context. Otherwise, this will throw an error: `TypeError: Cannot read
properties of undefined (reading 'Symbol(Symbol.species)')`.
  • Loading branch information
arturovt committed Mar 16, 2022
1 parent 5f7c4f6 commit 3832751
Showing 1 changed file with 11 additions and 2 deletions.
13 changes: 11 additions & 2 deletions packages/zone.js/lib/common/promise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,15 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
onFulfilled?: ((value: R) => TResult1 | PromiseLike<TResult1>)|undefined|null,
onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>)|undefined|
null): Promise<TResult1|TResult2> {
let C = (this.constructor as any)[Symbol.species];
// We must read `Symbol.species` safely because `this` may be anything. For instance, `this`
// may be an object without a prototype (created through `Object.create(null)`); thus
// `this.constructor` will be undefined. One of the use cases is SystemJS creating
// prototype-less objects (modules) via `Object.create(null)`. The SystemJS creates an empty
// object and copies promise properties into that object (within the `getOrCreateLoad`
// function). The zone.js then checks if the resolved value has the `then` method and invokes
// it with the `value` context. Otherwise, this will throw an error: `TypeError: Cannot read
// properties of undefined (reading 'Symbol(Symbol.species)')`.
let C = (this.constructor as any)?.[Symbol.species];
if (!C || typeof C !== 'function') {
C = this.constructor || ZoneAwarePromise;
}
Expand All @@ -483,7 +491,8 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
}

finally<U>(onFinally?: () => U | PromiseLike<U>): Promise<R> {
let C = (this.constructor as any)[Symbol.species];
// See comment on the call to `then` about why thee `Symbol.species` is safely accessed.
let C = (this.constructor as any)?.[Symbol.species];
if (!C || typeof C !== 'function') {
C = ZoneAwarePromise;
}
Expand Down

0 comments on commit 3832751

Please sign in to comment.