Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

types: type support for event modifiers #12675

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions packages-private/dts-test/h.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,51 @@ describe('h inference w/ element', () => {
onClick: e => {
expectType<MouseEvent>(e)
},
onClickCapture: e => {
expectType<MouseEvent>(e)
},
onClickCaptureOnce: e => {
expectType<MouseEvent>(e)
},
onClickCaptureOncePassive: e => {
expectType<MouseEvent>(e)
},
onClickCapturePassive: e => {
expectType<MouseEvent>(e)
},
onClickCapturePassiveOnce: e => {
expectType<MouseEvent>(e)
},
onClickOnce: e => {
expectType<MouseEvent>(e)
},
onClickOnceCapture: e => {
expectType<MouseEvent>(e)
},
onClickOnceCapturePassive: e => {
expectType<MouseEvent>(e)
},
onClickOncePassive: e => {
expectType<MouseEvent>(e)
},
onClickOncePassiveCapture: e => {
expectType<MouseEvent>(e)
},
onClickPassive: e => {
expectType<MouseEvent>(e)
},
onClickPassiveCapture: e => {
expectType<MouseEvent>(e)
},
onClickPassiveCaptureOnce: e => {
expectType<MouseEvent>(e)
},
onClickPassiveOnce: e => {
expectType<MouseEvent>(e)
},
onClickPassiveOnceCapture: e => {
expectType<MouseEvent>(e)
},
})
h('input', {
onFocus(e) {
Expand Down
46 changes: 46 additions & 0 deletions packages-private/dts-test/tsx.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,52 @@ expectType<JSX.Element>(
// infer correct event type
expectType<EventTarget | null>(e.target)
}}
onInputCapture={e => {
expectType<EventTarget | null>(e.target)
}}
onInputCaptureOnce={e => {
expectType<EventTarget | null>(e.target)
}}
onInputCaptureOncePassive={e => {
expectType<EventTarget | null>(e.target)
}}
onInputCapturePassive={e => {
expectType<EventTarget | null>(e.target)
}}
onInputCapturePassiveOnce={e => {
expectType<EventTarget | null>(e.target)
}}
onInputOnce={e => {
expectType<EventTarget | null>(e.target)
}}
onInputOnceCapture={e => {
expectType<EventTarget | null>(e.target)
}}
onInputOnceCapturePassive={e => {
expectType<EventTarget | null>(e.target)
}}
onInputOncePassive={e => {
expectType<EventTarget | null>(e.target)
}}
onInputOncePassiveCapture={e => {
expectType<EventTarget | null>(e.target)
}}
onInputPassive={e => {
// infer correct event type
expectType<EventTarget | null>(e.target)
}}
onInputPassiveCapture={e => {
expectType<EventTarget | null>(e.target)
}}
onInputPassiveCaptureOnce={e => {
expectType<EventTarget | null>(e.target)
}}
onInputPassiveOnce={e => {
expectType<EventTarget | null>(e.target)
}}
onInputPassiveOnceCapture={e => {
expectType<EventTarget | null>(e.target)
}}
/>,
)

Expand Down
8 changes: 7 additions & 1 deletion packages/runtime-core/src/h.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,14 @@ interface Constructor<P = any> {
new (...args: any[]): { $props: P }
}

type CombineModifiers<T extends string, U extends string = T> = T extends any
? T | `${T}${CombineModifiers<Exclude<U, T>>}`
: never

type EventModifiers = CombineModifiers<'Capture' | 'Once' | 'Passive'> | ''

type HTMLElementEventHandler = {
[K in keyof HTMLElementEventMap as `on${Capitalize<K>}`]?: (
[K in keyof HTMLElementEventMap as `on${Capitalize<K>}${EventModifiers}`]?: (
ev: HTMLElementEventMap[K],
) => any
}
Expand Down
16 changes: 10 additions & 6 deletions packages/runtime-dom/src/jsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ export type StyleValue =
| CSSProperties
| Array<StyleValue>

export interface HTMLAttributes extends AriaAttributes, EventHandlers<Events> {
export interface HTMLAttributes extends AriaAttributes, EventHandlers {
innerHTML?: string

class?: any
Expand Down Expand Up @@ -808,7 +808,7 @@ export interface WebViewHTMLAttributes extends HTMLAttributes {
webpreferences?: string
}

export interface SVGAttributes extends AriaAttributes, EventHandlers<Events> {
export interface SVGAttributes extends AriaAttributes, EventHandlers {
innerHTML?: string

/**
Expand Down Expand Up @@ -1384,10 +1384,14 @@ export interface Events {
onTransitionstart: TransitionEvent
}

type EventHandlers<E> = {
[K in keyof E]?: E[K] extends (...args: any) => any
? E[K]
: (payload: E[K]) => void
type CombineModifiers<T extends string, U extends string = T> = T extends any
? T | `${T}${CombineModifiers<Exclude<U, T>>}`
: never

type EventModifiers = CombineModifiers<'Capture' | 'Once' | 'Passive'> | ''

type EventHandlers = {
[K in keyof Events as `${K}${EventModifiers}`]?: (payload: Events[K]) => void
}

import type { VNodeRef } from '@vue/runtime-core'
Expand Down
Loading