diff --git a/packages/runtime-core/__tests__/scheduler.spec.ts b/packages/runtime-core/__tests__/scheduler.spec.ts index c06b9afb3e3..6246a87e8f7 100644 --- a/packages/runtime-core/__tests__/scheduler.spec.ts +++ b/packages/runtime-core/__tests__/scheduler.spec.ts @@ -546,4 +546,16 @@ describe('scheduler', () => { await nextTick() expect(spy).toHaveBeenCalledTimes(1) }) + + it('nextTick should return promise', async () => { + const fn = vi.fn(() => { + return 1 + }) + + const p = nextTick(fn) + + expect(p).toBeInstanceOf(Promise) + expect(await p).toBe(1) + expect(fn).toHaveBeenCalledTimes(1) + }) }) diff --git a/packages/runtime-core/src/scheduler.ts b/packages/runtime-core/src/scheduler.ts index 923f3ec8251..64c70ab59ca 100644 --- a/packages/runtime-core/src/scheduler.ts +++ b/packages/runtime-core/src/scheduler.ts @@ -1,5 +1,5 @@ import { ErrorCodes, callWithErrorHandling } from './errorHandling' -import { isArray, NOOP } from '@vue/shared' +import { Awaited, isArray, NOOP } from '@vue/shared' import { ComponentInternalInstance, getComponentName } from './component' import { warn } from './warning' @@ -50,10 +50,10 @@ let currentFlushPromise: Promise | null = null const RECURSION_LIMIT = 100 type CountMap = Map -export function nextTick( +export function nextTick( this: T, - fn?: (this: T) => void -): Promise { + fn?: (this: T) => R +): Promise> { const p = currentFlushPromise || resolvedPromise return fn ? p.then(this ? fn.bind(this) : fn) : p } diff --git a/packages/shared/src/typeUtils.ts b/packages/shared/src/typeUtils.ts index 67fb47c23b3..1deb4729125 100644 --- a/packages/shared/src/typeUtils.ts +++ b/packages/shared/src/typeUtils.ts @@ -12,3 +12,12 @@ export type LooseRequired = { [P in keyof (T & Required)]: T[P] } // If the type T accepts type "any", output type Y, otherwise output type N. // https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360 export type IfAny = 0 extends 1 & T ? Y : N + +// To prevent users with TypeScript versions lower than 4.5 from encountering unsupported Awaited type, a copy has been made here. +export type Awaited = T extends null | undefined + ? T // special case for `null | undefined` when not in `--strictNullChecks` mode + : T extends object & { then(onfulfilled: infer F, ...args: infer _): any } // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped + ? F extends (value: infer V, ...args: infer _) => any // if the argument to `then` is callable, extracts the first argument + ? Awaited // recursively unwrap the value + : never // the argument to `then` was not callable + : T // non-object or non-thenable