diff --git a/packages/core/src/defer/triggering.ts b/packages/core/src/defer/triggering.ts index bd8a0f86ee0..71438f55929 100644 --- a/packages/core/src/defer/triggering.ts +++ b/packages/core/src/defer/triggering.ts @@ -70,7 +70,7 @@ import { getTDeferBlockDetails, } from './utils'; import {ApplicationRef} from '../application/application_ref'; -import type {PromiseConstructor} from '../util/promise_with_resolvers'; +import {promiseWithResolvers} from '../util/promise_with_resolvers'; /** * Schedules triggering of a defer block for `on idle` and `on timer` conditions. @@ -549,7 +549,7 @@ function cleanupRemainingHydrationQueue( */ function populateHydratingStateForQueue(registry: DehydratedBlockRegistry, queue: string[]) { for (let blockId of queue) { - registry.hydrating.set(blockId, (Promise as unknown as PromiseConstructor).withResolvers()); + registry.hydrating.set(blockId, promiseWithResolvers()); } } diff --git a/packages/core/src/render3/instructions/animation.ts b/packages/core/src/render3/instructions/animation.ts index b3b54cbb327..d94f8ceea03 100644 --- a/packages/core/src/render3/instructions/animation.ts +++ b/packages/core/src/render3/instructions/animation.ts @@ -19,7 +19,7 @@ import {Renderer} from '../interfaces/renderer'; import {NgZone} from '../../zone'; import {determineLongestAnimation, allLeavingAnimations} from '../../animation/longest_animation'; import {TNode} from '../interfaces/node'; -import type {PromiseConstructor} from '../../util/promise_with_resolvers'; +import {promiseWithResolvers} from '../../util/promise_with_resolvers'; import { areAnimationsDisabled, @@ -230,7 +230,7 @@ function runLeaveAnimations( value: string | Function, animationsDisabled: boolean, ): Promise { - const {promise, resolve} = (Promise as unknown as PromiseConstructor).withResolvers(); + const {promise, resolve} = promiseWithResolvers(); const nativeElement = getNativeByTNode(tNode, lView) as Element; ngDevMode && assertElementNodes(nativeElement, 'animate.leave'); @@ -363,7 +363,7 @@ function runLeaveAnimationFunction( tNode: TNode, value: AnimationFunction, ): Promise { - const {promise, resolve} = (Promise as unknown as PromiseConstructor).withResolvers(); + const {promise, resolve} = promiseWithResolvers(); const nativeElement = getNativeByTNode(tNode, lView) as Element; ngDevMode && assertElementNodes(nativeElement, 'animate.leave'); diff --git a/packages/core/src/util/promise_with_resolvers.ts b/packages/core/src/util/promise_with_resolvers.ts index f86386f6fe7..28dbc6ed739 100644 --- a/packages/core/src/util/promise_with_resolvers.ts +++ b/packages/core/src/util/promise_with_resolvers.ts @@ -27,3 +27,25 @@ export interface PromiseConstructor { */ withResolvers(): PromiseWithResolvers; } + +/** + * Replace with `Promise.withResolvers()` once it's available. + * NET September 2026 + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers. + */ +export function promiseWithResolvers(): { + promise: Promise; + resolve: (value: T | PromiseLike) => void; + reject: (reason?: any) => void; +} { + let resolve!: (value: T | PromiseLike) => void; + let reject!: (reason?: any) => void; + + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + + return {promise, resolve, reject}; +} diff --git a/packages/core/test/resource/resource_spec.ts b/packages/core/test/resource/resource_spec.ts index e640ba15336..9473a6c6d4d 100644 --- a/packages/core/test/resource/resource_spec.ts +++ b/packages/core/test/resource/resource_spec.ts @@ -18,8 +18,7 @@ import { signal, } from '../../src/core'; import {TestBed} from '../../testing'; - -import type {PromiseConstructor} from '../../src/util/promise_with_resolvers'; +import {promiseWithResolvers} from '../../src/util/promise_with_resolvers'; abstract class MockBackend { protected pending = new Map< @@ -337,7 +336,7 @@ describe('resource', () => { const res = resource({ params: request, loader: async ({params}) => { - const p = (Promise as unknown as PromiseConstructor).withResolvers(); + const p = promiseWithResolvers(); resolve.push(() => p.resolve(params)); return p.promise; },