-import { defineComponent } from 'vue'
+import { type DefineComponent, type Directive, defineComponent } from 'vue'
import { expectType } from './utils'
declare module 'vue' {
test?(n: number): void
}
+ interface GlobalDirectives {
+ test: Directive
+ }
+
+ interface GlobalComponents {
+ RouterView: DefineComponent<{}>
+ }
+
interface ComponentCustomProperties {
state?: 'stopped' | 'running'
}
},
})
+expectType<Directive>(Custom.directives!.test)
+expectType<DefineComponent<{}>>(Custom.components!.RouterView)
expectType<JSX.Element>(<Custom baz={1} />)
expectType<JSX.Element>(<Custom custom={1} baz={1} />)
expectType<JSX.Element>(<Custom bar="bar" baz={1} />)
describe('withKeys and withModifiers as pro', () => {
const onKeydown = withKeys(e => {}, [''])
+ // @ts-expect-error invalid modifiers
const onClick = withModifiers(e => {}, [''])
;<input onKeydown={onKeydown} onClick={onClick} />
})
+// #3367 expose components types
+describe('expose component types', () => {
+ const child = defineComponent({
+ props: {
+ a: String,
+ },
+ })
+
+ const parent = defineComponent({
+ components: {
+ child,
+ child2: {
+ template: `<div></div>`,
+ },
+ },
+ })
+
+ expectType<typeof child>(parent.components!.child)
+ expectType<Component>(parent.components!.child2)
+
+ // global components
+ expectType<Readonly<KeepAliveProps>>(
+ new parent.components!.KeepAlive().$props,
+ )
+ expectType<Readonly<KeepAliveProps>>(new child.components!.KeepAlive().$props)
+
+ // runtime-dom components
+ expectType<Readonly<TransitionProps>>(
+ new parent.components!.Transition().$props,
+ )
+ expectType<Readonly<TransitionProps>>(
+ new child.components!.Transition().$props,
+ )
+})
+
+describe('directive typing', () => {
+ const customDirective: Directive = {
+ created(_) {},
+ }
+
+ const comp = defineComponent({
+ props: {
+ a: String,
+ },
+ directives: {
+ customDirective,
+ localDirective: {
+ created(_, { arg }) {
+ expectType<string | undefined>(arg)
+ },
+ },
+ },
+ })
+
+ expectType<typeof customDirective>(comp.directives!.customDirective)
+ expectType<Directive>(comp.directives!.localDirective)
+
+ // global directive
+ expectType<typeof vShow>(comp.directives!.vShow)
+})
+
+describe('expose typing', () => {
+ const Comp = defineComponent({
+ expose: ['a', 'b'],
+ props: {
+ some: String,
+ },
+ data() {
+ return { a: 1, b: '2', c: 1 }
+ },
+ })
+
+ expectType<Array<'a' | 'b'>>(Comp.expose!)
+
+ const vm = new Comp()
+ // internal should still be exposed
+ vm.$props
+
+ expectType<number>(vm.a)
+ expectType<string>(vm.b)
+
+ // @ts-expect-error shouldn't be exposed
+ vm.c
+})
+
import type {
AllowedComponentProps,
ComponentCustomProps,
ComponentOptionsMixin,
DefineComponent,
+ Directive,
EmitsOptions,
ExtractPropTypes,
+ KeepAliveProps,
+ TransitionProps,
VNodeProps,
+ vShow,
} from 'vue'
// code generated by tsc / vue-tsc, make sure this continues to work
--- /dev/null
+import { type Directive, type ObjectDirective, vModelText } from 'vue'
+import { describe, expectType } from './utils'
+
+type ExtractBinding<T> = T extends (
+ el: any,
+ binding: infer B,
+ vnode: any,
+ prev: any,
+) => any
+ ? B
+ : never
+
+declare function testDirective<
+ Value,
+ Modifiers extends string = string,
+ Arg extends string = string,
+>(): ExtractBinding<Directive<any, Value, Modifiers, Arg>>
+
+describe('vmodel', () => {
+ expectType<ObjectDirective<any, any, 'trim' | 'number' | 'lazy', string>>(
+ vModelText,
+ )
+ // @ts-expect-error
+ expectType<ObjectDirective<any, any, 'not-valid', string>>(vModelText)
+})
+
+describe('custom', () => {
+ expectType<{
+ value: number
+ oldValue: number | null
+ arg?: 'Arg'
+ modifiers: Record<'a' | 'b', boolean>
+ }>(testDirective<number, 'a' | 'b', 'Arg'>())
+
+ expectType<{
+ value: number
+ oldValue: number | null
+ arg?: 'Arg'
+ modifiers: Record<'a' | 'b', boolean>
+ // @ts-expect-error
+ }>(testDirective<number, 'a', 'Arg'>())
+
+ expectType<{
+ value: number
+ oldValue: number | null
+ arg?: 'Arg'
+ modifiers: Record<'a' | 'b', boolean>
+ // @ts-expect-error
+ }>(testDirective<number, 'a' | 'b', 'Argx'>())
+
+ expectType<{
+ value: number
+ oldValue: number | null
+ arg?: 'Arg'
+ modifiers: Record<'a' | 'b', boolean>
+ // @ts-expect-error
+ }>(testDirective<string, 'a' | 'b', 'Arg'>())
+})
ComponentOptionsWithArrayProps,
ComponentOptionsWithObjectProps,
ComponentOptionsWithoutProps,
+ ComponentProvideOptions,
ComputedOptions,
MethodOptions,
RenderFunction,
} from './componentOptions'
import type {
AllowedComponentProps,
+ Component,
ComponentCustomProps,
+ GlobalComponents,
+ GlobalDirectives,
SetupContext,
} from './component'
import type {
CreateComponentPublicInstance,
} from './componentPublicInstance'
import type { SlotsType } from './componentSlots'
+import type { Directive } from './directives'
export type PublicProps = VNodeProps &
AllowedComponentProps &
Props = ResolveProps<PropsOrPropOptions, E>,
Defaults = ExtractDefaultPropTypes<PropsOrPropOptions>,
S extends SlotsType = {},
+ LC extends Record<string, Component> = {},
+ Directives extends Record<string, Directive> = {},
+ Exposed extends string = string,
+ Provide extends ComponentProvideOptions = ComponentProvideOptions,
> = ComponentPublicInstanceConstructor<
CreateComponentPublicInstance<
Props,
Defaults,
true,
{},
- S
+ S,
+ LC & GlobalComponents,
+ Directives & GlobalDirectives,
+ Exposed
>
> &
ComponentOptionsBase<
Defaults,
{},
string,
- S
+ S,
+ LC & GlobalComponents,
+ Directives & GlobalDirectives,
+ Exposed,
+ Provide
> &
PP
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = {},
EE extends string = string,
- S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string,
+ S extends SlotsType = {},
+ LC extends Record<string, Component> = {},
+ Directives extends Record<string, Directive> = {},
+ Exposed extends string = string,
+ Provide extends ComponentProvideOptions = ComponentProvideOptions,
>(
options: ComponentOptionsWithoutProps<
Props,
EE,
I,
II,
- S
+ S,
+ LC,
+ Directives,
+ Exposed,
+ Provide
>,
): DefineComponent<
Props,
PublicProps,
ResolveProps<Props, E>,
ExtractDefaultPropTypes<Props>,
- S
+ S,
+ LC,
+ Directives,
+ Exposed,
+ Provide
>
// overload 3: object format with array props declaration
S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string,
+ LC extends Record<string, Component> = {},
+ Directives extends Record<string, Directive> = {},
+ Exposed extends string = string,
+ Provide extends ComponentProvideOptions = ComponentProvideOptions,
Props = Readonly<{ [key in PropNames]?: any }>,
>(
options: ComponentOptionsWithArrayProps<
EE,
I,
II,
- S
+ S,
+ LC,
+ Directives,
+ Exposed,
+ Provide
>,
): DefineComponent<
Props,
PublicProps,
ResolveProps<Props, E>,
ExtractDefaultPropTypes<Props>,
- S
+ S,
+ LC,
+ Directives,
+ Exposed,
+ Provide
>
// overload 4: object format with object props declaration
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = {},
EE extends string = string,
- S extends SlotsType = {},
I extends ComponentInjectOptions = {},
II extends string = string,
+ S extends SlotsType = {},
+ LC extends Record<string, Component> = {},
+ Directives extends Record<string, Directive> = {},
+ Exposed extends string = string,
+ Provide extends ComponentProvideOptions = ComponentProvideOptions,
>(
options: ComponentOptionsWithObjectProps<
PropsOptions,
EE,
I,
II,
- S
+ S,
+ LC,
+ Directives,
+ Exposed,
+ Provide
>,
): DefineComponent<
PropsOptions,
PublicProps,
ResolveProps<PropsOptions, E>,
ExtractDefaultPropTypes<PropsOptions>,
- S
+ S,
+ LC,
+ Directives,
+ Exposed,
+ Provide
>
// implementation, close to no-op
import type { SchedulerJob } from './scheduler'
import type { LifecycleHooks } from './enums'
+// Augment GlobalComponents
+import type { TeleportProps } from './components/Teleport'
+import type { SuspenseProps } from './components/Suspense'
+import type { KeepAliveProps } from './components/KeepAlive'
+import type { BaseTransitionProps } from './components/BaseTransition'
+import type { DefineComponent } from './apiDefineComponent'
+
export type Data = Record<string, unknown>
/**
*/
export interface ComponentCustomProps {}
+/**
+ * For globally defined Directives
+ * Here is an example of adding a directive `VTooltip` as global directive:
+ *
+ * @example
+ * ```ts
+ * import VTooltip from 'v-tooltip'
+ *
+ * declare module '@vue/runtime-core' {
+ * interface GlobalDirectives {
+ * VTooltip
+ * }
+ * }
+ * ```
+ */
+export interface GlobalDirectives extends Record<string, Directive> {}
+
+/**
+ * For globally defined Components
+ * Here is an example of adding a component `RouterView` as global component:
+ *
+ * @example
+ * ```ts
+ * import { RouterView } from 'vue-router'
+ *
+ * declare module '@vue/runtime-core' {
+ * interface GlobalComponents {
+ * RouterView
+ * }
+ * }
+ * ```
+ */
+export interface GlobalComponents extends Record<string, Component> {
+ Teleport: DefineComponent<TeleportProps>
+ Suspense: DefineComponent<SuspenseProps>
+ KeepAlive: DefineComponent<KeepAliveProps>
+ BaseTransition: DefineComponent<BaseTransitionProps>
+}
+
/**
* Default allowed non-declared props on component in TSX
*/
I extends ComponentInjectOptions = {},
II extends string = string,
S extends SlotsType = {},
-> extends LegacyOptions<Props, D, C, M, Mixin, Extends, I, II>,
+ LC extends Record<string, Component> = {},
+ Directives extends Record<string, Directive> = {},
+ Exposed extends string = string,
+ Provide extends ComponentProvideOptions = ComponentProvideOptions,
+> extends LegacyOptions<Props, D, C, M, Mixin, Extends, I, II, Provide>,
ComponentInternalOptions,
ComponentCustomOptions {
setup?: (
// Luckily `render()` doesn't need any arguments nor does it care about return
// type.
render?: Function
- components?: Record<string, Component>
- directives?: Record<string, Directive>
+ // NOTE: extending both LC and Record<string, Component> allows objects to be forced
+ // to be of type Component, while still inferring LC generic
+ components?: LC & Record<string, Component>
+ // NOTE: extending both Directives and Record<string, Directive> allows objects to be forced
+ // to be of type Directive, while still inferring Directives generic
+ directives?: Directives & Record<string, Directive>
inheritAttrs?: boolean
emits?: (E | EE[]) & ThisType<void>
slots?: S
- // TODO infer public instance type based on exposed keys
- expose?: string[]
+ expose?: Exposed[]
serverPrefetch?(): void | Promise<any>
// Runtime compiler only -----------------------------------------------------
I extends ComponentInjectOptions = {},
II extends string = string,
S extends SlotsType = {},
+ LC extends Record<string, Component> = {},
+ Directives extends Record<string, Directive> = {},
+ Exposed extends string = string,
+ Provide extends ComponentProvideOptions = ComponentProvideOptions,
PE = Props & EmitsToProps<E>,
> = ComponentOptionsBase<
PE,
{},
I,
II,
- S
+ S,
+ LC,
+ Directives,
+ Exposed,
+ Provide
> & {
props?: undefined
} & ThisType<
{},
false,
I,
- S
+ S,
+ LC,
+ Directives,
+ Exposed
>
>
I extends ComponentInjectOptions = {},
II extends string = string,
S extends SlotsType = {},
+ LC extends Record<string, Component> = {},
+ Directives extends Record<string, Directive> = {},
+ Exposed extends string = string,
+ Provide extends ComponentProvideOptions = ComponentProvideOptions,
Props = Prettify<Readonly<{ [key in PropNames]?: any } & EmitsToProps<E>>>,
> = ComponentOptionsBase<
Props,
{},
I,
II,
- S
+ S,
+ LC,
+ Directives,
+ Exposed,
+ Provide
> & {
props: PropNames[]
} & ThisType<
{},
false,
I,
- S
+ S,
+ LC,
+ Directives,
+ Exposed
>
>
I extends ComponentInjectOptions = {},
II extends string = string,
S extends SlotsType = {},
+ LC extends Record<string, Component> = {},
+ Directives extends Record<string, Directive> = {},
+ Exposed extends string = string,
+ Provide extends ComponentProvideOptions = ComponentProvideOptions,
Props = Prettify<Readonly<ExtractPropTypes<PropsOptions> & EmitsToProps<E>>>,
Defaults = ExtractDefaultPropTypes<PropsOptions>,
> = ComponentOptionsBase<
Defaults,
I,
II,
- S
+ S,
+ LC,
+ Directives,
+ Exposed,
+ Provide
> & {
props: PropsOptions & ThisType<void>
} & ThisType<
Defaults,
false,
I,
- S
+ S,
+ LC,
+ Directives
>
>
Mixin extends ComponentOptionsMixin = any,
Extends extends ComponentOptionsMixin = any,
E extends EmitsOptions = any,
- S extends SlotsType = any,
+ EE extends string = string,
+ Defaults = {},
+ I extends ComponentInjectOptions = {},
+ II extends string = string,
+ S extends SlotsType = {},
+ LC extends Record<string, Component> = {},
+ Directives extends Record<string, Directive> = {},
+ Exposed extends string = string,
+ Provide extends ComponentProvideOptions = ComponentProvideOptions,
> = ComponentOptionsBase<
Props,
RawBindings,
Mixin,
Extends,
E,
- string,
- S
+ EE,
+ Defaults,
+ I,
+ II,
+ S,
+ LC,
+ Directives,
+ Exposed,
+ Provide
> &
ThisType<
CreateComponentPublicInstance<
Mixin,
Extends,
E,
- Readonly<Props>
+ Readonly<Props>,
+ Defaults,
+ false,
+ I,
+ S,
+ LC,
+ Directives
>
>
any,
any,
any,
+ any,
+ any,
+ any,
+ any,
+ any,
+ any,
any
>
Extends extends ComponentOptionsMixin,
I extends ComponentInjectOptions,
II extends string,
+ Provide extends ComponentProvideOptions = ComponentProvideOptions,
> {
compatConfig?: CompatConfig
computed?: C
methods?: M
watch?: ComponentWatchOptions
- provide?: ComponentProvideOptions
+ provide?: Provide
inject?: I | II[]
// assets
import {
+ type Component,
type ComponentInternalInstance,
type Data,
getExposeProxy,
type ComponentInjectOptions,
type ComponentOptionsBase,
type ComponentOptionsMixin,
+ type ComponentProvideOptions,
type ComputedOptions,
type ExtractComputedReturns,
type InjectToObject,
import { currentRenderingInstance } from './componentRenderContext'
import { warn } from './warning'
import { installCompatInstanceProperties } from './compat/instance'
+import type { Directive } from './directives'
/**
* Custom properties added to component instances in any way and can be accessed through `this`
infer Defaults,
any,
any,
+ any,
+ any,
+ any,
+ any,
any
>
? OptionTypesType<P & {}, B & {}, D & {}, C & {}, M & {}, Defaults & {}> &
MakeDefaultsOptional extends boolean = false,
I extends ComponentInjectOptions = {},
S extends SlotsType = {},
+ LC extends Record<string, Component> = {},
+ Directives extends Record<string, Directive> = {},
+ Exposed extends string = string,
PublicMixin = IntersectionMixin<Mixin> & IntersectionMixin<Extends>,
PublicP = UnwrapMixinsType<PublicMixin, 'P'> & EnsureNonVoid<P>,
PublicB = UnwrapMixinsType<PublicMixin, 'B'> & EnsureNonVoid<B>,
EnsureNonVoid<M>,
PublicDefaults = UnwrapMixinsType<PublicMixin, 'Defaults'> &
EnsureNonVoid<Defaults>,
+ Provide extends ComponentProvideOptions = ComponentProvideOptions,
> = ComponentPublicInstance<
PublicP,
PublicB,
Defaults,
{},
string,
- S
+ S,
+ LC,
+ Directives,
+ Exposed,
+ Provide
>,
I,
- S
+ S,
+ Exposed
>
+
+export type ExposedKeys<
+ T,
+ Exposed extends string & keyof T,
+> = '' extends Exposed ? T : Pick<T, Exposed>
+
// public properties exposed on the proxy, which is used as the render context
// in templates (as `this` in the render option)
export type ComponentPublicInstance<
Options = ComponentOptionsBase<any, any, any, any, any, any, any, any, any>,
I extends ComponentInjectOptions = {},
S extends SlotsType = {},
+ Exposed extends string = '',
> = {
$: ComponentInternalInstance
$data: D
: (...args: any) => any,
options?: WatchOptions,
): WatchStopHandle
-} & IfAny<P, P, Omit<P, keyof ShallowUnwrapRef<B>>> &
- ShallowUnwrapRef<B> &
- UnwrapNestedRefs<D> &
- ExtractComputedReturns<C> &
- M &
- ComponentCustomProperties &
- InjectToObject<I>
+} & ExposedKeys<
+ IfAny<P, P, Omit<P, keyof ShallowUnwrapRef<B>>> &
+ ShallowUnwrapRef<B> &
+ UnwrapNestedRefs<D> &
+ ExtractComputedReturns<C> &
+ M &
+ ComponentCustomProperties &
+ InjectToObject<I>,
+ Exposed
+>
export type PublicPropertiesMap = Record<
string,
import { pauseTracking, resetTracking } from '@vue/reactivity'
import { traverse } from './apiWatch'
-export interface DirectiveBinding<V = any> {
+export interface DirectiveBinding<
+ Value = any,
+ Modifiers extends string = string,
+ Arg extends string = string,
+> {
instance: ComponentPublicInstance | null
- value: V
- oldValue: V | null
- arg?: string
- modifiers: DirectiveModifiers
- dir: ObjectDirective<any, V>
+ value: Value
+ oldValue: Value | null
+ arg?: Arg
+ modifiers: DirectiveModifiers<Modifiers>
+ dir: ObjectDirective<any, Value>
}
-export type DirectiveHook<T = any, Prev = VNode<any, T> | null, V = any> = (
- el: T,
- binding: DirectiveBinding<V>,
- vnode: VNode<any, T>,
+export type DirectiveHook<
+ HostElement = any,
+ Prev = VNode<any, HostElement> | null,
+ Value = any,
+ Modifiers extends string = string,
+ Arg extends string = string,
+> = (
+ el: HostElement,
+ binding: DirectiveBinding<Value, Modifiers, Arg>,
+ vnode: VNode<any, HostElement>,
prevVNode: Prev,
) => void
vnode: VNode,
) => Data | undefined
-export interface ObjectDirective<T = any, V = any> {
- created?: DirectiveHook<T, null, V>
- beforeMount?: DirectiveHook<T, null, V>
- mounted?: DirectiveHook<T, null, V>
- beforeUpdate?: DirectiveHook<T, VNode<any, T>, V>
- updated?: DirectiveHook<T, VNode<any, T>, V>
- beforeUnmount?: DirectiveHook<T, null, V>
- unmounted?: DirectiveHook<T, null, V>
+export interface ObjectDirective<
+ HostElement = any,
+ Value = any,
+ Modifiers extends string = string,
+ Arg extends string = string,
+> {
+ created?: DirectiveHook<HostElement, null, Value, Modifiers, Arg>
+ beforeMount?: DirectiveHook<HostElement, null, Value, Modifiers, Arg>
+ mounted?: DirectiveHook<HostElement, null, Value, Modifiers, Arg>
+ beforeUpdate?: DirectiveHook<
+ HostElement,
+ VNode<any, HostElement>,
+ Value,
+ Modifiers,
+ Arg
+ >
+ updated?: DirectiveHook<
+ HostElement,
+ VNode<any, HostElement>,
+ Value,
+ Modifiers,
+ Arg
+ >
+ beforeUnmount?: DirectiveHook<HostElement, null, Value, Modifiers, Arg>
+ unmounted?: DirectiveHook<HostElement, null, Value, Modifiers, Arg>
getSSRProps?: SSRDirectiveHook
deep?: boolean
}
-export type FunctionDirective<T = any, V = any> = DirectiveHook<T, any, V>
+export type FunctionDirective<
+ HostElement = any,
+ V = any,
+ Modifiers extends string = string,
+ Arg extends string = string,
+> = DirectiveHook<HostElement, any, V, Modifiers, Arg>
-export type Directive<T = any, V = any> =
- | ObjectDirective<T, V>
- | FunctionDirective<T, V>
+export type Directive<
+ HostElement = any,
+ Value = any,
+ Modifiers extends string = string,
+ Arg extends string = string,
+> =
+ | ObjectDirective<HostElement, Value, Modifiers, Arg>
+ | FunctionDirective<HostElement, Value, Modifiers, Arg>
-export type DirectiveModifiers = Record<string, boolean>
+export type DirectiveModifiers<K extends string = string> = Record<K, boolean>
export function validateDirectiveName(name: string) {
if (isBuiltInDirective(name)) {
SetupContext,
ComponentCustomProps,
AllowedComponentProps,
+ GlobalComponents,
+ GlobalDirectives,
ComponentInstance,
} from './component'
export type {
--- /dev/null
+// Note: this file is auto concatenated to the end of the bundled d.ts during
+// build.
+
+declare module '@vue/runtime-core' {
+ export interface GlobalComponents {
+ Teleport: DefineComponent<TeleportProps>
+ Suspense: DefineComponent<SuspenseProps>
+ KeepAlive: DefineComponent<KeepAliveProps>
+ BaseTransition: DefineComponent<BaseTransitionProps>
+ }
+}
})
test('it should support key modifiers and system modifiers', () => {
- const keyNames = ['ctrl', 'shift', 'meta', 'alt']
+ const keyNames = ['ctrl', 'shift', 'meta', 'alt'] as const
keyNames.forEach(keyName => {
const el = document.createElement('div')
const assignKey = Symbol('_assign')
-type ModelDirective<T> = ObjectDirective<
- T & { [assignKey]: AssignerFn; _assigning?: boolean }
+type ModelDirective<T, Modifiers extends string = string> = ObjectDirective<
+ T & { [assignKey]: AssignerFn; _assigning?: boolean },
+ any,
+ Modifiers
>
// We are exporting the v-model runtime directly as vnode hooks so that it can
// be tree-shaken in case v-model is never used.
export const vModelText: ModelDirective<
- HTMLInputElement | HTMLTextAreaElement
+ HTMLInputElement | HTMLTextAreaElement,
+ 'trim' | 'number' | 'lazy'
> = {
created(el, { modifiers: { lazy, trim, number } }, vnode) {
el[assignKey] = getModelAssigner(vnode)
},
}
-export const vModelSelect: ModelDirective<HTMLSelectElement> = {
+export const vModelSelect: ModelDirective<HTMLSelectElement, 'number'> = {
// <select multiple> value need to be deep traversed
deep: true,
created(el, { value, modifiers: { number } }, vnode) {
}
}
}
+
+export type VModelDirective =
+ | typeof vModelText
+ | typeof vModelCheckbox
+ | typeof vModelSelect
+ | typeof vModelRadio
+ | typeof vModelDynamic
import {
type ComponentInternalInstance,
DeprecationTypes,
+ type Directive,
type LegacyConfig,
compatUtils,
getCurrentInstance,
} from '@vue/runtime-core'
import { hyphenate, isArray } from '@vue/shared'
-const systemModifiers = ['ctrl', 'shift', 'alt', 'meta']
+const systemModifiers = ['ctrl', 'shift', 'alt', 'meta'] as const
+type SystemModifiers = (typeof systemModifiers)[number]
+type CompatModifiers = keyof typeof keyNames
+export type VOnModifiers = SystemModifiers | ModifierGuards | CompatModifiers
type KeyedEvent = KeyboardEvent | MouseEvent | TouchEvent
-const modifierGuards: Record<
- string,
- (e: Event, modifiers: string[]) => void | boolean
-> = {
- stop: e => e.stopPropagation(),
- prevent: e => e.preventDefault(),
- self: e => e.target !== e.currentTarget,
- ctrl: e => !(e as KeyedEvent).ctrlKey,
- shift: e => !(e as KeyedEvent).shiftKey,
- alt: e => !(e as KeyedEvent).altKey,
- meta: e => !(e as KeyedEvent).metaKey,
- left: e => 'button' in e && (e as MouseEvent).button !== 0,
- middle: e => 'button' in e && (e as MouseEvent).button !== 1,
- right: e => 'button' in e && (e as MouseEvent).button !== 2,
+const modifierGuards = {
+ stop: (e: Event) => e.stopPropagation(),
+ prevent: (e: Event) => e.preventDefault(),
+ self: (e: Event) => e.target !== e.currentTarget,
+ ctrl: (e: Event) => !(e as KeyedEvent).ctrlKey,
+ shift: (e: Event) => !(e as KeyedEvent).shiftKey,
+ alt: (e: Event) => !(e as KeyedEvent).altKey,
+ meta: (e: Event) => !(e as KeyedEvent).metaKey,
+ left: (e: Event) => 'button' in e && (e as MouseEvent).button !== 0,
+ middle: (e: Event) => 'button' in e && (e as MouseEvent).button !== 1,
+ right: (e: Event) => 'button' in e && (e as MouseEvent).button !== 2,
exact: (e, modifiers) =>
systemModifiers.some(m => (e as any)[`${m}Key`] && !modifiers.includes(m)),
-}
+} satisfies Record<
+ string,
+ | ((e: Event) => void | boolean)
+ | ((e: Event, modifiers: string[]) => void | boolean)
+>
+
+type ModifierGuards = keyof typeof modifierGuards
/**
* @private
T extends (event: Event, ...args: unknown[]) => any,
>(
fn: T & { _withMods?: { [key: string]: T } },
- modifiers: string[],
+ modifiers: VOnModifiers[],
) => {
const cache = fn._withMods || (fn._withMods = {})
const cacheKey = modifiers.join('.')
cache[cacheKey] ||
(cache[cacheKey] = ((event, ...args) => {
for (let i = 0; i < modifiers.length; i++) {
- const guard = modifierGuards[modifiers[i]]
+ const guard = modifierGuards[modifiers[i] as ModifierGuards]
if (guard && guard(event, modifiers)) return
}
return fn(event, ...args)
// Kept for 2.x compat.
// Note: IE11 compat for `spacebar` and `del` is removed for now.
-const keyNames: Record<string, string | string[]> = {
+const keyNames = {
esc: 'escape',
space: ' ',
up: 'arrow-up',
right: 'arrow-right',
down: 'arrow-down',
delete: 'backspace',
-}
+} satisfies Record<string, string | string[]>
/**
* @private
}
const eventKey = hyphenate(event.key)
- if (modifiers.some(k => k === eventKey || keyNames[k] === eventKey)) {
+ if (
+ modifiers.some(
+ k =>
+ k === eventKey ||
+ keyNames[k as unknown as CompatModifiers] === eventKey,
+ )
+ ) {
return fn(event)
}
}) as T)
)
}
+
+export type VOnDirective = Directive<any, any, VOnModifiers>
import {
type App,
type CreateAppFunction,
+ type DefineComponent,
DeprecationTypes,
+ type Directive,
type ElementNamespace,
type HydrationRenderer,
type Renderer,
isSVGTag,
isString,
} from '@vue/shared'
+import type { TransitionProps } from './components/Transition'
+import type { TransitionGroupProps } from './components/TransitionGroup'
+import type { vShow } from './directives/vShow'
+import type { VOnDirective } from './directives/vOn'
+import type { VModelDirective } from './directives/vModel'
declare module '@vue/reactivity' {
export interface RefUnwrapBailTypes {
}
}
+declare module '@vue/runtime-core' {
+ interface GlobalComponents {
+ Transition: DefineComponent<TransitionProps>
+ TransitionGroup: DefineComponent<TransitionGroupProps>
+ }
+
+ interface GlobalDirectives {
+ vShow: typeof vShow
+ vOn: VOnDirective
+ vBind: VModelDirective
+ vIf: Directive<any, boolean>
+ VOnce: Directive
+ VSlot: Directive
+ }
+}
+
const rendererOptions = /*#__PURE__*/ extend({ patchProp }, nodeOps)
// lazy create the renderer - this makes core renderer logic tree-shakable
components: {
child: {
compatConfig: { RENDER_FUNCTION: false },
- render() {
+ render(this: LegacyPublicInstance) {
normalSlots = this.$slots
scopedSlots = this.$scopedSlots
},