Skip to content

Commit 6a22b1f

Browse files
fix(types): ensure nextTick return type reflect correct Promise value (#8406)
1 parent 438027c commit 6a22b1f

File tree

3 files changed

+25
-4
lines changed

3 files changed

+25
-4
lines changed

packages/runtime-core/__tests__/scheduler.spec.ts

+12
Original file line numberDiff line numberDiff line change
@@ -546,4 +546,16 @@ describe('scheduler', () => {
546546
await nextTick()
547547
expect(spy).toHaveBeenCalledTimes(1)
548548
})
549+
550+
it('nextTick should return promise', async () => {
551+
const fn = vi.fn(() => {
552+
return 1
553+
})
554+
555+
const p = nextTick(fn)
556+
557+
expect(p).toBeInstanceOf(Promise)
558+
expect(await p).toBe(1)
559+
expect(fn).toHaveBeenCalledTimes(1)
560+
})
549561
})

packages/runtime-core/src/scheduler.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ErrorCodes, callWithErrorHandling } from './errorHandling'
2-
import { isArray, NOOP } from '@vue/shared'
2+
import { Awaited, isArray, NOOP } from '@vue/shared'
33
import { ComponentInternalInstance, getComponentName } from './component'
44
import { warn } from './warning'
55

@@ -50,10 +50,10 @@ let currentFlushPromise: Promise<void> | null = null
5050
const RECURSION_LIMIT = 100
5151
type CountMap = Map<SchedulerJob, number>
5252

53-
export function nextTick<T = void>(
53+
export function nextTick<T = void, R = void>(
5454
this: T,
55-
fn?: (this: T) => void
56-
): Promise<void> {
55+
fn?: (this: T) => R
56+
): Promise<Awaited<R>> {
5757
const p = currentFlushPromise || resolvedPromise
5858
return fn ? p.then(this ? fn.bind(this) : fn) : p
5959
}

packages/shared/src/typeUtils.ts

+9
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,12 @@ export type LooseRequired<T> = { [P in keyof (T & Required<T>)]: T[P] }
1212
// If the type T accepts type "any", output type Y, otherwise output type N.
1313
// https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360
1414
export type IfAny<T, Y, N> = 0 extends 1 & T ? Y : N
15+
16+
// To prevent users with TypeScript versions lower than 4.5 from encountering unsupported Awaited<T> type, a copy has been made here.
17+
export type Awaited<T> = T extends null | undefined
18+
? T // special case for `null | undefined` when not in `--strictNullChecks` mode
19+
: 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
20+
? F extends (value: infer V, ...args: infer _) => any // if the argument to `then` is callable, extracts the first argument
21+
? Awaited<V> // recursively unwrap the value
22+
: never // the argument to `then` was not callable
23+
: T // non-object or non-thenable

0 commit comments

Comments
 (0)