From fc557f0276aefe523e328cad984eddb3ba7fecdb Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Fri, 13 Feb 2026 09:23:43 -0800 Subject: [PATCH] fix(zone.js): support passthrough of Promise.try API When Zone patches Promise, it uses ZoneAwarePromise. The new Promise.try API was undefined on ZoneAwarePromise, making it unavailable when zone was present. This change gracefully passes through Promise.try to the native Promise implementation, if available, without patching it to execute in the right zone (our stance is not to add new patches but avoid destructively making new APIs unavailable). Fixes #67057 --- packages/zone.js/lib/common/promise.ts | 5 +++ packages/zone.js/test/common/Promise.spec.ts | 33 ++++++++++++++++++++ packages/zone.js/test/test_fake_polyfill.ts | 13 ++++++++ 3 files changed, 51 insertions(+) diff --git a/packages/zone.js/lib/common/promise.ts b/packages/zone.js/lib/common/promise.ts index d561ae6be9d..7eca3b29958 100644 --- a/packages/zone.js/lib/common/promise.ts +++ b/packages/zone.js/lib/common/promise.ts @@ -627,6 +627,11 @@ export function patchPromise(Zone: ZoneType): void { if (NativePromise) { patchThen(NativePromise); + // TODO(atscott): Investigate generic to propagate any unknown properties + const nativeTry = (NativePromise as any)['try']; + if (nativeTry && typeof nativeTry === 'function') { + (ZoneAwarePromise as any)['try'] = nativeTry; + } patchMethod(global, 'fetch', (delegate) => zoneify(delegate)); } diff --git a/packages/zone.js/test/common/Promise.spec.ts b/packages/zone.js/test/common/Promise.spec.ts index 9257f740ebc..29533a3df32 100644 --- a/packages/zone.js/test/common/Promise.spec.ts +++ b/packages/zone.js/test/common/Promise.spec.ts @@ -969,5 +969,38 @@ describe( reject(error); }); }); + + describe('Promise.try', () => { + it('should resolve', (done: DoneFn) => { + (Promise as any) + .try(() => 1) + .then((v: any) => { + expect(v).toBe(1); + done(); + }); + }); + it('should reject on throw', (done: DoneFn) => { + const error = new Error('test'); + (Promise as any) + .try(() => { + throw error; + }) + .catch((e: any) => { + expect(e).toBe(error); + done(); + }); + }); + it('should execute in the correct zone', (done: DoneFn) => { + const zone = Zone.current.fork({name: 'promise-try'}); + zone.run(() => { + (Promise as any) + .try(() => 1) + .then(() => { + expect(Zone.current.name).toEqual(zone.name); + done(); + }); + }); + }); + }); }), ); diff --git a/packages/zone.js/test/test_fake_polyfill.ts b/packages/zone.js/test/test_fake_polyfill.ts index 34f12bdcdfb..b60ad768574 100644 --- a/packages/zone.js/test/test_fake_polyfill.ts +++ b/packages/zone.js/test/test_fake_polyfill.ts @@ -17,6 +17,19 @@ export function setupFakePolyfill(): void { NativeError.customProperty = 'customProperty'; NativeError.customFunction = function () {}; + // Polyfill Promise.try for testing pass-through + if (global.Promise && typeof global.Promise.try !== 'function') { + global.Promise.try = function (callback: any) { + return new global.Promise((resolve: any, reject: any) => { + try { + resolve(callback()); + } catch (e) { + reject(e); + } + }); + }; + } + // add fake cordova polyfill for test const fakeCordova = function () {};