Skip to content

Commit

Permalink
fix(createEventHook): make createEventHook union type can be inferred…
Browse files Browse the repository at this point in the history
… correctly (#3569)
  • Loading branch information
Doctor-wu committed Dec 4, 2023
1 parent fd67ba3 commit e48ca07
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 1 deletion.
13 changes: 13 additions & 0 deletions packages/shared/createEventHook/index.test.ts
Expand Up @@ -93,6 +93,19 @@ describe('createEventHook', () => {
expect(result).toEqual([2])
})

it('should pass union type', () => {
let count = 0

const { on: onResult, trigger } = createEventHook<number | string>()

// union type should be inferred
onResult(value => count = 2)
trigger(1)
trigger(2)

expect(count).toBe(2)
})

it('the same listener should fire only once', () => {
const listener = vi.fn()
const { on, trigger, off } = createEventHook<string>()
Expand Down
12 changes: 11 additions & 1 deletion packages/shared/createEventHook/index.ts
Expand Up @@ -2,9 +2,19 @@
* The source code for this function was inspired by vue-apollo's `useEventHook` util
* https://github.com/vuejs/vue-apollo/blob/v4/packages/vue-apollo-composable/src/util/useEventHook.ts
*/
import type { IsAny } from '../utils/types'
import { tryOnScopeDispose } from '../tryOnScopeDispose'

type Callback<T> = T extends void ? () => void : (param: T) => void
// any extends void = true
// so we need to check if T is any first
type Callback<T> = IsAny<T> extends true
? (param: any) => void
: (
[T] extends [void]
? () => void
: (param: T) => void
)

export type EventHookOn<T = any> = (fn: Callback<T>) => { off: () => void }
export type EventHookOff<T = any> = (fn: Callback<T>) => void
export type EventHookTrigger<T = any> = (param?: T) => Promise<unknown[]>
Expand Down
7 changes: 7 additions & 0 deletions packages/shared/utils/types.ts
Expand Up @@ -148,3 +148,10 @@ export type MapOldSources<T, Immediate> = {
}

export type Mutable<T> = { -readonly [P in keyof T]: T[P] }

// https://stackoverflow.com/questions/55541275/typescript-check-for-the-any-type
export type IfAny<T, Y, N> = 0 extends (1 & T) ? Y : N
/**
* will return `true` if `T` is `any`, or `false` otherwise
*/
export type IsAny<T> = IfAny<T, true, false>

0 comments on commit e48ca07

Please sign in to comment.