From 6cabf7f84e62662c39e3164c0ac695cfa024a67c Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Tue, 14 Nov 2023 15:20:54 +0000 Subject: [PATCH 01/15] fix preparing type helpers --- src/vnodeTransformers/stubComponentsTransformer.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vnodeTransformers/stubComponentsTransformer.ts b/src/vnodeTransformers/stubComponentsTransformer.ts index 7f1a110fd..10220f4b6 100644 --- a/src/vnodeTransformers/stubComponentsTransformer.ts +++ b/src/vnodeTransformers/stubComponentsTransformer.ts @@ -17,7 +17,7 @@ import { ComponentPropsOptions, ComponentObjectPropsOptions, Component, - ComponentOptions + AsyncComponentOptions } from 'vue' import { hyphenate } from '../utils/vueShared' import { matchName } from '../utils/matchName' @@ -123,11 +123,14 @@ export const createStub = ({ } }) - const { __asyncLoader: asyncLoader } = type as ComponentOptions + const { __asyncLoader: asyncLoader } = type as { + __asyncLoader?: AsyncComponentOptions['loader'] + } if (asyncLoader) { asyncLoader().then(() => { registerStub({ - source: (type as ComponentOptions).__asyncResolved, + source: (type as { __asyncResolved: ConcreteComponent | undefined }) + .__asyncResolved!, stub }) }) From 2e0e1a655926f611785ec6fedaad31dbcdfa5368 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Wed, 15 Nov 2023 11:17:23 +0000 Subject: [PATCH 02/15] some improvements and added missing types on VueWrapper --- src/mount.ts | 55 +++++++++++++++++++++---------------------- src/renderToString.ts | 45 +++++++++++++++++++++++++---------- src/vueWrapper.ts | 48 +++++++++++++++++++++++++++++-------- 3 files changed, 98 insertions(+), 50 deletions(-) diff --git a/src/mount.ts b/src/mount.ts index 4abf1c42e..d6c653425 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -1,9 +1,11 @@ -import { ComponentPublicInstance, DefineComponent, VNode } from 'vue' -import type { - ComponentExposed, +import { + ComponentPublicInstance, + DefineComponent, + VNode, ComponentProps, - ComponentSlots -} from 'vue-component-type-helpers' + ComponentInstance +} from 'vue' +import type { ComponentSlots } from 'vue-component-type-helpers' import { createInstance } from './createInstance' import { MountingOptions } from './types' import { trackInstance } from './utils/autoUnmount' @@ -18,10 +20,10 @@ type WithArray = T | T[] type ComponentData = T extends { data?(...args: any): infer D } ? D : {} -export type ComponentMountingOptions< - T, - P extends ComponentProps = ComponentProps -> = Omit>, 'slots'> & { +export type ComponentMountingOptions = Omit< + MountingOptions>, + 'slots' +> & { slots?: { [K in keyof ComponentSlots]: WithArray< | ShimSlotReturnType[K]> @@ -33,28 +35,25 @@ export type ComponentMountingOptions< } } & Record +// defineComponent export function mount< - T, - C = T extends ((...args: any) => any) | (new (...args: any) => any) - ? T - : T extends { props?: infer Props } - ? DefineComponent< - Props extends Readonly<(infer PropNames)[]> | (infer PropNames)[] - ? { [key in PropNames extends string ? PropNames : string]?: any } - : Props - > - : DefineComponent, - P extends ComponentProps = ComponentProps + T extends DefineComponent< + PropsOrOptions, + any, + any, + any, + any, + any, + any, + any, + any, + any + >, + PropsOrOptions >( originalComponent: T, - options?: ComponentMountingOptions -): VueWrapper< - ComponentProps & ComponentData & ComponentExposed, - ComponentPublicInstance< - ComponentProps, - ComponentData & ComponentExposed & Omit> - > -> + options?: ComponentMountingOptions> +): VueWrapper> // implementation export function mount( diff --git a/src/renderToString.ts b/src/renderToString.ts index 0e666e8b9..21860ae98 100644 --- a/src/renderToString.ts +++ b/src/renderToString.ts @@ -1,23 +1,44 @@ import { renderToString as baseRenderToString } from '@vue/server-renderer' -import { DefineComponent } from 'vue' +import { ComponentProps, DefineComponent } from 'vue' import { createInstance } from './createInstance' import { ComponentMountingOptions } from './mount' import { RenderMountingOptions } from './types' +// export function renderToString< +// T, +// C = T extends ((...args: any) => any) | (new (...args: any) => any) +// ? T +// : T extends { props?: infer Props } +// ? DefineComponent< +// Props extends Readonly<(infer PropNames)[]> | (infer PropNames)[] +// ? { [key in PropNames extends string ? PropNames : string]?: any } +// : Props +// > +// : DefineComponent +// >( +// originalComponent: T, +// options?: ComponentMountingOptions & +// Pick, 'attachTo'> +// ): Promise + +// defineComponent export function renderToString< - T, - C = T extends ((...args: any) => any) | (new (...args: any) => any) - ? T - : T extends { props?: infer Props } - ? DefineComponent< - Props extends Readonly<(infer PropNames)[]> | (infer PropNames)[] - ? { [key in PropNames extends string ? PropNames : string]?: any } - : Props - > - : DefineComponent + T extends DefineComponent< + PropsOrOptions, + any, + any, + any, + any, + any, + any, + any, + any, + any + >, + PropsOrOptions >( originalComponent: T, - options?: ComponentMountingOptions & + options?: ComponentMountingOptions> & Pick, 'attachTo'> ): Promise diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 0209dbb4d..effdc4774 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -1,4 +1,10 @@ -import { nextTick, App, ComponentPublicInstance, VNode } from 'vue' +import { + nextTick, + App, + ComponentPublicInstance, + VNode, + ExtractComponentEmits +} from 'vue' import { config } from './config' import domEvents from './constants/dom-events' @@ -72,9 +78,24 @@ function createVMProxy( }) } +type ResolveComponentEmitKeys = keyof ResolveEmitRecord + +type ResolveEmitRecord = ExtractComponentEmits extends infer E + ? [E] extends [Array] + ? Record + : { + [K in keyof E]: (E[K] extends (...args: infer Args) => any + ? Args extends { length: 0 } + ? void + : Args extends { length: 1 } + ? Args[0] + : Args + : void)[] + } + : never + export class VueWrapper< - VM = unknown, - T extends ComponentPublicInstance = VM & ComponentPublicInstance + T extends ComponentPublicInstance = ComponentPublicInstance > extends BaseWrapper { private readonly componentVM: T private readonly rootVM: ComponentPublicInstance | undefined | null @@ -226,11 +247,11 @@ export class VueWrapper< return selector ? props[selector] : props } - emitted(): Record - emitted(eventName: string): undefined | T[] - emitted( - eventName?: string - ): undefined | T[] | Record { + emitted(): ResolveEmitRecord + emitted>( + eventName: E + ): undefined | ResolveEmitRecord[E] + emitted(eventName?: string) { return emitted(this.vm, eventName) } @@ -239,7 +260,7 @@ export class VueWrapper< return domWrapper.isVisible() } - setData(data: Record): Promise { + setData(data: Partial): Promise { mergeDeep(this.componentVM.$data, data) return nextTick() } @@ -253,7 +274,14 @@ export class VueWrapper< return nextTick() } - setValue(value: unknown, prop?: string): Promise { + setValue< + V extends T['$props'] extends { modelValue?: infer MV } ? MV : never + >(value: V): Promise + setValue

( + value: T['$props'][P], + prop: P + ): Promise + setValue(value: unknown, prop?: unknown): Promise { const propEvent = prop || 'modelValue' this.vm.$emit(`update:${propEvent}`, value) return this.vm.$nextTick() From 79e89e67b0ccae8698059df6092f9997108f755e Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Thu, 16 Nov 2023 10:32:17 +0000 Subject: [PATCH 03/15] more changes --- src/baseWrapper.ts | 78 ++++++++++++++++++++++++++------ src/interfaces/wrapperLike.ts | 12 +++-- src/mount.ts | 9 +++- src/types.ts | 2 +- src/vueWrapper.ts | 20 +++++++- test-dts/findComponent.d-test.ts | 20 +++++--- test-dts/mount.d-test.ts | 2 +- test-dts/wrapper.d-test.ts | 7 ++- 8 files changed, 119 insertions(+), 31 deletions(-) diff --git a/src/baseWrapper.ts b/src/baseWrapper.ts index 71f074bf5..59edd07c2 100644 --- a/src/baseWrapper.ts +++ b/src/baseWrapper.ts @@ -1,13 +1,19 @@ import { textContent } from './utils' import type { TriggerOptions } from './createDomEvent' import { + ComponentDefineOptions, + ComponentInjectOptions, + ComponentInstance, ComponentInternalInstance, ComponentOptions, + ComponentOptionsMixin, ComponentPublicInstance, ComputedOptions, CreateComponentPublicInstance, + EmitsOptions, FunctionalComponent, MethodOptions, + SlotsType, nextTick } from 'vue' import { createDOMEvent } from './createDomEvent' @@ -108,16 +114,58 @@ export default abstract class BaseWrapper // searching by string without specifying component results in WrapperLike object findComponent(selector: string): WrapperLike + // Find Component Options aka plain object findComponent< - Props, - RawBindings = any, - D = any, - C extends ComputedOptions = ComputedOptions, - M extends MethodOptions = MethodOptions + Props = {}, + RawBindings = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + E extends EmitsOptions = {}, + EE extends string = string, + I extends ComponentInjectOptions = {}, + II extends string = string, + S extends SlotsType = {}, + Options = {} >( - selector: ComponentOptions - ): VueWrapper> + selector: ComponentDefineOptions< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S, + Options + > + ): VueWrapper< + Props extends DefinedComponent + ? ComponentInstance + : CreateComponentPublicInstance< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + Props, + {}, + true, + I, + S, + Options + > + > findComponent( selector: string ): VueWrapper< @@ -129,17 +177,19 @@ export default abstract class BaseWrapper infer M > ? CreateComponentPublicInstance - : VueWrapper + : CreateComponentPublicInstance > - // searching for component created via defineComponent results in VueWrapper of proper type - findComponent( - selector: T | Exclude - ): VueWrapper> // searching for functional component results in DOMWrapper findComponent(selector: T): DOMWrapper findComponent( selector: string ): DOMWrapper + + // searching for component created via defineComponent results in VueWrapper of proper type + findComponent( + selector: T | Exclude + ): VueWrapper> + // searching by name or ref always results in VueWrapper findComponent( selector: NameSelector | RefSelector @@ -185,7 +235,7 @@ export default abstract class BaseWrapper findAllComponents(selector: string): WrapperLike[] findAllComponents( selector: T | Exclude - ): VueWrapper>[] + ): VueWrapper>[] findAllComponents( selector: T ): DOMWrapper[] @@ -292,7 +342,7 @@ export default abstract class BaseWrapper getComponent(selector: string): Omit getComponent( selector: T | Exclude - ): Omit>, 'exists'> + ): Omit>, 'exists'> // searching for functional component results in DOMWrapper getComponent( selector: T | string diff --git a/src/interfaces/wrapperLike.ts b/src/interfaces/wrapperLike.ts index 50728db60..8d32d1b1b 100644 --- a/src/interfaces/wrapperLike.ts +++ b/src/interfaces/wrapperLike.ts @@ -8,7 +8,11 @@ import { RefSelector } from '../types' import { VueWrapper } from '../vueWrapper' -import { ComponentPublicInstance, FunctionalComponent } from 'vue' +import { + ComponentInstance, + ComponentPublicInstance, + FunctionalComponent +} from 'vue' import type { DOMWrapper } from '../domWrapper' export default interface WrapperLike { @@ -35,7 +39,7 @@ export default interface WrapperLike { findComponent(selector: string): WrapperLike findComponent( selector: T | Exclude - ): VueWrapper> + ): VueWrapper> findComponent( selector: T | string ): DOMWrapper @@ -50,7 +54,7 @@ export default interface WrapperLike { findAllComponents(selector: string): WrapperLike[] findAllComponents( selector: T | Exclude - ): VueWrapper>[] + ): VueWrapper>[] findAllComponents( selector: string ): DOMWrapper[] @@ -79,7 +83,7 @@ export default interface WrapperLike { getComponent(selector: string): Omit getComponent( selector: T | Exclude - ): Omit>, 'exists'> + ): Omit>, 'exists'> // searching for functional component results in DOMWrapper getComponent( selector: T | string diff --git a/src/mount.ts b/src/mount.ts index d6c653425..8b09a5348 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -35,6 +35,14 @@ export type ComponentMountingOptions = Omit< } } & Record +// export function mount( +// originalComponent: T, +// options?: ComponentMountingOptions> +// ): //VueWrapper> +// { +// props: ComponentProps +// } + // defineComponent export function mount< T extends DefineComponent< @@ -54,7 +62,6 @@ export function mount< originalComponent: T, options?: ComponentMountingOptions> ): VueWrapper> - // implementation export function mount( inputComponent: any, diff --git a/src/types.ts b/src/types.ts index 46677534b..f649a7a1e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -166,4 +166,4 @@ export type VueNode = T & { export type VueElement = VueNode -export type DefinedComponent = new (...args: any[]) => any +export type DefinedComponent = Component diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index effdc4774..ed8c09187 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -3,7 +3,8 @@ import { App, ComponentPublicInstance, VNode, - ExtractComponentEmits + ExtractComponentEmits, + ComponentCustomProperties } from 'vue' import { config } from './config' @@ -94,8 +95,23 @@ type ResolveEmitRecord = ExtractComponentEmits extends infer E } : never +declare const aaa: keyof Omit< + ComponentPublicInstance, + keyof ComponentCustomProperties +> + +// type BetterKeys = keyof Omit< +// ComponentPublicInstance, +// keyof ComponentCustomProperties +// > +// export type ComponentInstance = { +// [K in keyof ComponentPublicInstance]?: any +// } & Record + export class VueWrapper< - T extends ComponentPublicInstance = ComponentPublicInstance + T extends Omit & { + $emit: any + } = ComponentPublicInstance > extends BaseWrapper { private readonly componentVM: T private readonly rootVM: ComponentPublicInstance | undefined | null diff --git a/test-dts/findComponent.d-test.ts b/test-dts/findComponent.d-test.ts index deb64e1d1..e667876a4 100644 --- a/test-dts/findComponent.d-test.ts +++ b/test-dts/findComponent.d-test.ts @@ -1,5 +1,5 @@ import { expectType } from './index' -import { defineComponent } from 'vue' +import { ComponentInstance, defineComponent } from 'vue' import { DOMWrapper, mount, VueWrapper } from '../src' import WrapperLike from '../src/interfaces/wrapperLike' @@ -31,11 +31,13 @@ const wrapper = mount(AppWithDefine) // find by type - component definition const componentByType = wrapper.findComponent(ComponentToFind) -expectType>>(componentByType) +expectType>>( + componentByType +) // find by type - component definition with emits const componentWithEmitsByType = wrapper.findComponent(ComponentWithEmits) -expectType>>( +expectType>>( componentWithEmitsByType ) @@ -50,7 +52,7 @@ expectType(componentByString) // findi by string with specifying component const componentByStringWithParam = wrapper.findComponent('.foo') -expectType>>( +expectType>>( componentByStringWithParam ) @@ -66,7 +68,7 @@ expectType(componentByRef) const componentByRefWithType = wrapper.findComponent({ ref: 'foo' }) -expectType>>( +expectType>>( componentByRefWithType ) @@ -78,6 +80,12 @@ expectType(componentByName) const componentByNameWithType = wrapper.findComponent({ name: 'foo' }) -expectType>>( + + +declare const aaa : ComponentInstance +aaa.$props +componentByNameWithType.vm.$props + +expectType>>( componentByNameWithType ) diff --git a/test-dts/mount.d-test.ts b/test-dts/mount.d-test.ts index 46c42aa45..511a8953a 100644 --- a/test-dts/mount.d-test.ts +++ b/test-dts/mount.d-test.ts @@ -85,7 +85,7 @@ mount(AppWithProps, { expectError( mount(AppWithProps, { - // @ts-expect-error wrong prop type should not compile + // @ts-expect-error wrong prop type should not compile props: { a: 2 } }) ) diff --git a/test-dts/wrapper.d-test.ts b/test-dts/wrapper.d-test.ts index 1582f3d95..cf3b86236 100644 --- a/test-dts/wrapper.d-test.ts +++ b/test-dts/wrapper.d-test.ts @@ -3,6 +3,9 @@ import { defineComponent } from 'vue' import { mount } from '../src' const AppWithDefine = defineComponent({ + emits: { + increment: (arg: { count: number }) => true + }, template: '' }) @@ -65,10 +68,10 @@ expectType(byClassArray[0].element) // event name without specific type let incrementEventWithoutType = wrapper.emitted('increment') -expectType(incrementEventWithoutType) +expectType<{ count: number }[] | undefined>(incrementEventWithoutType) // event name -let incrementEvent = wrapper.emitted<{ count: number }>('increment') +let incrementEvent = wrapper.emitted('increment') expectType<{ count: number }[] | undefined>(incrementEvent) expectType<{ count: number }>(incrementEvent![0]) From e0b69640f310a0e7a6f5365a47fd6c180d2579cf Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Thu, 16 Nov 2023 10:37:17 +0000 Subject: [PATCH 04/15] couple more changes --- src/mount.ts | 12 ++---------- test-dts/mount.d-test.ts | 1 - 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/mount.ts b/src/mount.ts index 8b09a5348..8dc47ac7e 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -2,7 +2,6 @@ import { ComponentPublicInstance, DefineComponent, VNode, - ComponentProps, ComponentInstance } from 'vue' import type { ComponentSlots } from 'vue-component-type-helpers' @@ -11,6 +10,7 @@ import { MountingOptions } from './types' import { trackInstance } from './utils/autoUnmount' import { VueWrapper } from './vueWrapper' import { createVueWrapper } from './wrapperFactory' +import { ComponentPropsWithDefaultOptional } from 'vue' type ShimSlotReturnType = T extends (...args: infer P) => any ? (...args: P) => any @@ -35,14 +35,6 @@ export type ComponentMountingOptions = Omit< } } & Record -// export function mount( -// originalComponent: T, -// options?: ComponentMountingOptions> -// ): //VueWrapper> -// { -// props: ComponentProps -// } - // defineComponent export function mount< T extends DefineComponent< @@ -60,7 +52,7 @@ export function mount< PropsOrOptions >( originalComponent: T, - options?: ComponentMountingOptions> + options?: ComponentMountingOptions> ): VueWrapper> // implementation export function mount( diff --git a/test-dts/mount.d-test.ts b/test-dts/mount.d-test.ts index 511a8953a..c9400fc71 100644 --- a/test-dts/mount.d-test.ts +++ b/test-dts/mount.d-test.ts @@ -168,7 +168,6 @@ mount(ShimComponent, { } }) -// TODO it should work mount(ShimComponent, { data() { return { From 87b35f8b91f09a4fb585046cd51459b23c0796f7 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Thu, 16 Nov 2023 10:37:28 +0000 Subject: [PATCH 05/15] adding the vue patch dependency --- package.json | 3 + patches/@vue__runtime-core@3.3.8.patch | 314 +++++++++++++++++++++++++ pnpm-lock.yaml | 10 +- test-dts/tsconfig.tsd.json | 13 +- 4 files changed, 329 insertions(+), 11 deletions(-) create mode 100644 patches/@vue__runtime-core@3.3.8.patch diff --git a/package.json b/package.json index d51fbfb70..b2bdd3be7 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,9 @@ "react", "react-dom" ] + }, + "patchedDependencies": { + "@vue/runtime-core@3.3.8": "patches/@vue__runtime-core@3.3.8.patch" } } } diff --git a/patches/@vue__runtime-core@3.3.8.patch b/patches/@vue__runtime-core@3.3.8.patch new file mode 100644 index 000000000..2f87f00d0 --- /dev/null +++ b/patches/@vue__runtime-core@3.3.8.patch @@ -0,0 +1,314 @@ +diff --git a/dist/runtime-core.d.ts b/dist/runtime-core.d.ts +index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..93ad7c6ac81064255901ac6319a31a6853ac491e 100644 +--- a/dist/runtime-core.d.ts ++++ b/dist/runtime-core.d.ts +@@ -1,7 +1,7 @@ + import { computed as computed$1, ShallowUnwrapRef, UnwrapNestedRefs, DebuggerEvent, ComputedGetter, WritableComputedOptions, Ref, ReactiveEffect, ComputedRef, DebuggerOptions, reactive } from '@vue/reactivity'; + export { ComputedGetter, ComputedRef, ComputedSetter, CustomRefFactory, DebuggerEvent, DebuggerEventExtraInfo, DebuggerOptions, DeepReadonly, EffectScheduler, EffectScope, MaybeRef, MaybeRefOrGetter, Raw, ReactiveEffect, ReactiveEffectOptions, ReactiveEffectRunner, ReactiveFlags, Ref, ShallowReactive, ShallowRef, ShallowUnwrapRef, ToRef, ToRefs, TrackOpTypes, TriggerOpTypes, UnwrapNestedRefs, UnwrapRef, WritableComputedOptions, WritableComputedRef, customRef, effect, effectScope, getCurrentScope, isProxy, isReactive, isReadonly, isRef, isShallow, markRaw, onScopeDispose, proxyRefs, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, stop, toRaw, toRef, toRefs, toValue, triggerRef, unref } from '@vue/reactivity'; + import { IfAny, Prettify, Awaited, UnionToIntersection, LooseRequired } from '@vue/shared'; +-export { camelize, capitalize, normalizeClass, normalizeProps, normalizeStyle, toDisplayString, toHandlerKey } from '@vue/shared'; ++export { LooseRequired, camelize, capitalize, normalizeClass, normalizeProps, normalizeStyle, toDisplayString, toHandlerKey } from '@vue/shared'; + + export declare const computed: typeof computed$1; + +@@ -101,17 +101,32 @@ type ExtractMixin = { + type IntersectionMixin = IsDefaultMixinComponent extends true ? OptionTypesType : UnionToIntersection>; + type UnwrapMixinsType = T extends OptionTypesType ? T[Type] : never; + type EnsureNonVoid = T extends void ? {} : T; +-type ComponentPublicInstanceConstructor = ComponentPublicInstance, Props = any, RawBindings = any, D = any, C extends ComputedOptions = ComputedOptions, M extends MethodOptions = MethodOptions> = { ++/** ++ * ++ P = {}, // props type extracted from props option ++ B = {}, // raw bindings returned from setup() ++ D = {}, // return from data() ++ C extends ComputedOptions = {}, ++ M extends MethodOptions = {}, ++ E extends EmitsOptions = {}, ++ PublicProps = P, ++ Defaults = {}, ++ MakeDefaultsOptional extends boolean = false, ++ Options = ComponentOptionsBase, ++ I extends ComponentInjectOptions = {}, ++ S extends SlotsType = {} ++ */ ++type ComponentPublicInstanceConstructor = ComponentPublicInstance, Props = any, RawBindings = any, D = any, C extends ComputedOptions = ComputedOptions, M extends MethodOptions = MethodOptions, E extends EmitsOptions = {}, PublicProps = {}, Defaults = {}, MakeDefaultsOptional extends boolean = false, Options = ComponentOptionsBase, I extends ComponentInjectOptions = {}, S extends SlotsType = {}> = { + __isFragment?: never; + __isTeleport?: never; + __isSuspense?: never; + new (...args: any[]): T; + }; +-export type CreateComponentPublicInstance

& IntersectionMixin, PublicP = UnwrapMixinsType & EnsureNonVoid

, PublicB = UnwrapMixinsType & EnsureNonVoid, PublicD = UnwrapMixinsType & EnsureNonVoid, PublicC extends ComputedOptions = UnwrapMixinsType & EnsureNonVoid, PublicM extends MethodOptions = UnwrapMixinsType & EnsureNonVoid, PublicDefaults = UnwrapMixinsType & EnsureNonVoid> = ComponentPublicInstance, I, S>; ++export type CreateComponentPublicInstance

, PublicMixin = IntersectionMixin & IntersectionMixin, PublicP = UnwrapMixinsType & EnsureNonVoid

, PublicB = UnwrapMixinsType & EnsureNonVoid, PublicD = UnwrapMixinsType & EnsureNonVoid, PublicC extends ComputedOptions = UnwrapMixinsType & EnsureNonVoid, PublicM extends MethodOptions = UnwrapMixinsType & EnsureNonVoid, PublicDefaults = UnwrapMixinsType & EnsureNonVoid> = ComponentPublicInstance; + export type ComponentPublicInstance

, I extends ComponentInjectOptions = {}, S extends SlotsType = {}> = { ++C extends ComputedOptions = {}, M extends MethodOptions = {}, E extends EmitsOptions = {}, PublicProps = P, Defaults = {}, MakeDefaultsOptional extends boolean = false, Options = any, I extends ComponentInjectOptions = {}, S extends SlotsType = {}> = { + $: ComponentInternalInstance; + $data: D; + $props: MakeDefaultsOptional extends true ? Partial & Omit & PublicProps, keyof Defaults> : Prettify

& PublicProps; +@@ -126,7 +141,7 @@ C extends ComputedOptions = {}, M extends MethodOptions = {}, E extends EmitsOpt + $forceUpdate: () => void; + $nextTick: typeof nextTick; + $watch any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R]) => any : (...args: any) => any, options?: WatchOptions): WatchStopHandle; +-} & P & ShallowUnwrapRef & UnwrapNestedRefs & ExtractComputedReturns & M & ComponentCustomProperties & InjectToObject; ++} & IfAny>> & ShallowUnwrapRef & UnwrapNestedRefs & ExtractComputedReturns & M & ComponentCustomProperties & InjectToObject; + + declare const enum LifecycleHooks { + BEFORE_CREATE = "bc", +@@ -383,6 +398,7 @@ export type ComponentPropsOptions

= ComponentObjectPropsOptions

| s + export type ComponentObjectPropsOptions

= { + [K in keyof P]: Prop | null; + }; ++ + export type Prop = PropOptions | PropType; + type DefaultFactory = (props: Data) => T | null | undefined; + interface PropOptions { +@@ -514,6 +530,15 @@ export type DirectiveArguments = Array<[Directive | undefined] | [Directive | un + */ + export declare function withDirectives(vnode: T, directives: DirectiveArguments): T; + ++interface ComponentOptionsCompat extends ComponentOptions { ++ model?: any; ++ el?: any; ++ _base?: any; ++ options?: any; ++ propsData?: any; ++ parent?: any; ++ __isBuildIn?: boolean; ++} + export declare const enum DeprecationTypes { + GLOBAL_MOUNT = "GLOBAL_MOUNT", + GLOBAL_MOUNT_CONTAINER = "GLOBAL_MOUNT_CONTAINER", +@@ -610,19 +635,19 @@ export interface RuntimeCompilerOptions { + comments?: boolean; + delimiters?: [string, string]; + } +-export type ComponentOptionsWithoutProps> = ComponentOptionsBase & { ++export type ComponentOptionsWithoutProps> = ComponentOptionsBase & { + props?: undefined; + } & ThisType>; +-export type ComponentOptionsWithArrayProps>>> = ComponentOptionsBase & { ++} & EmitsToProps>>> = Omit, 'props'> & { + props: PropNames[]; + } & ThisType>; +-export type ComponentOptionsWithObjectProps & EmitsToProps>>, Defaults = ExtractDefaultPropTypes> = ComponentOptionsBase & { +- props: PropsOptions & ThisType; ++export type ComponentOptionsWithObjectProps> : Prettify & EmitsToProps>>, Defaults = ExtractDefaultPropTypes> = ComponentOptionsBase & { ++ props: PropsOptions & ThisType; + } & ThisType>; +-export type ComponentOptions = ComponentOptionsBase & ThisType>>; +-export type ComponentOptionsMixin = ComponentOptionsBase; ++export type ComponentOptions, RawBindings = any, D = any, C extends ComputedOptions = any, M extends MethodOptions = any, Mixin extends ComponentOptionsMixin = any, Extends extends ComponentOptionsMixin = any, E extends EmitsOptions = {}, I extends ComponentInjectOptions = {}, S extends SlotsType = any> = ComponentOptionsBase & ThisType, {}, false, I, S>>; ++export type ComponentOptionsMixin = ComponentOptionsBase; + export type ComputedOptions = Record | WritableComputedOptions>; + export interface MethodOptions { + [key: string]: Function; +@@ -652,7 +677,7 @@ type InjectToObject = T extends string[] ? { + } : never; + interface LegacyOptions { + compatConfig?: CompatConfig; +- [key: string]: any; ++ props?: ComponentPropsOptions | Readonly; + data?: (this: CreateComponentPublicInstance, vm: CreateComponentPublicInstance) => D; + computed?: C; + methods?: M; +@@ -814,6 +839,7 @@ export interface TeleportProps { + disabled?: boolean; + } + declare const TeleportImpl: { ++ name: string; + __isTeleport: boolean; + process(n1: TeleportVNode | null, n2: TeleportVNode, container: RendererElement, anchor: RendererNode | null, parentComponent: ComponentInternalInstance | null, parentSuspense: SuspenseBoundary | null, isSVG: boolean, slotScopeIds: string[] | null, optimized: boolean, internals: RendererInternals): void; + remove(vnode: VNode, parentComponent: ComponentInternalInstance | null, parentSuspense: SuspenseBoundary | null, optimized: boolean, { um: unmount, o: { remove: hostRemove } }: RendererInternals, doRemove: boolean): void; +@@ -883,7 +909,7 @@ export type VNodeProps = { + onVnodeBeforeUnmount?: VNodeMountHook | VNodeMountHook[]; + onVnodeUnmounted?: VNodeMountHook | VNodeMountHook[]; + }; +-type VNodeChildAtom = VNode | typeof NULL_DYNAMIC_COMPONENT | string | number | boolean | null | undefined | void; ++type VNodeChildAtom = VNode | string | number | boolean | null | undefined | void; + export type VNodeArrayChildren = Array; + export type VNodeChild = VNodeChildAtom | VNodeArrayChildren; + export type VNodeNormalizedChildren = string | VNodeArrayChildren | RawSlots | null; +@@ -1037,7 +1063,7 @@ interface ClassComponent { + * values, e.g. checking if its a function or not. This is mostly for internal + * implementation code. + */ +-export type ConcreteComponent = ComponentOptions | FunctionalComponent; ++export type ConcreteComponent, RawBindings = any, D = any, C extends ComputedOptions = ComputedOptions, M extends MethodOptions = MethodOptions, E extends EmitsOptions = any, I extends ComponentInjectOptions = any, S extends SlotsType = any> = (ComponentOptions & Record) | FunctionalComponent; + /** + * A type used in public APIs where a component type is expected. + * The constructor type is an artificial type returned by defineComponent(). +@@ -1123,9 +1149,21 @@ export declare function watch, Immediate e + export declare function watch = false>(source: WatchSource, cb: WatchCallback, options?: WatchOptions): WatchStopHandle; + export declare function watch = false>(source: T, cb: WatchCallback, options?: WatchOptions): WatchStopHandle; + +-type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps; +-type ResolveProps = Readonly : PropsOrPropOptions> & ({} extends E ? {} : EmitsToProps); +-export type DefineComponent, Defaults = ExtractDefaultPropTypes, S extends SlotsType = {}> = ComponentPublicInstanceConstructor & Props> & ComponentOptionsBase & PP; ++type PublicProps$1 = VNodeProps & AllowedComponentProps & ComponentCustomProps; ++type ResolveProps = Readonly<([Props] extends [string] ? { ++ [key in Props]?: any; ++} : [Props] extends [ComponentObjectPropsOptions] ? ExtractPropTypes : Props extends never[] ? {} : Props) & ({} extends E ? {} : EmitsToProps)>; ++declare const RawOptionsSymbol: '__rawOptions'; ++export type DefineComponent, Defaults = ExtractDefaultPropTypes, I extends ComponentInjectOptions = {}, II extends string = string, S extends SlotsType = {}, Options = {}> = ComponentPublicInstanceConstructor> & Omit, 'props'> & { ++ props: PropsOrPropOptions; ++} & Omit & { ++ [RawOptionsSymbol]: Options; ++} & PP; ++export type ComponentDefineOptions = (Options & { ++ props?: [Props] extends [never] ? string[] : [Props] extends [string] ? Array : Props; ++} & ([Props] extends [string] ? ComponentOptionsWithArrayProps : [Props] extends [undefined] ? { ++ props?: undefined; ++} & ComponentOptionsWithoutProps<{}, RawBindings, D, C, M, Mixin, Extends, E, EE, I, II, S> : Props extends ComponentObjectPropsOptions ? ComponentOptionsWithObjectProps : ComponentOptions & EmitsToProps>, RawBindings, D, C, M, Mixin, Extends, E, I, S>)) | (((props: Props, ctx: SetupContext) => RenderFunction | Promise) & Options); + export declare function defineComponent, E extends EmitsOptions = {}, EE extends string = string, S extends SlotsType = {}>(setup: (props: Props, ctx: SetupContext) => RenderFunction | Promise, options?: Pick & { + props?: (keyof Props)[]; + emits?: E | EE[]; +@@ -1136,11 +1174,11 @@ export declare function defineComponent, E ext + emits?: E | EE[]; + slots?: S; + }): (props: Props & EmitsToProps) => any; +-export declare function defineComponent(options: ComponentOptionsWithoutProps): DefineComponent, ExtractDefaultPropTypes, S>; +-export declare function defineComponent>(options: ComponentOptionsWithArrayProps): DefineComponent, ExtractDefaultPropTypes, S>; +-export declare function defineComponent, RawBindings, D, C extends ComputedOptions = {}, M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = {}, EE extends string = string, S extends SlotsType = {}, I extends ComponentInjectOptions = {}, II extends string = string>(options: ComponentOptionsWithObjectProps): DefineComponent, ExtractDefaultPropTypes, S>; ++export declare function defineComponent(options: Options & ComponentOptionsWithoutProps): DefineComponent, ExtractDefaultPropTypes, I, II, S, Options>; ++export declare function defineComponent(options: ComponentDefineOptions): DefineComponent<[ ++ Props ++] extends [string] ? Props[] : undefined extends Props ? {} : Props extends never[] ? string[] : Props, RawBindings, D, C, M, Mixin, Extends, E, EE, PublicProps$1, ResolveProps, ExtractDefaultPropTypes, I, II, S, Options>; ++export declare function defineComponent(options: Options & ComponentOptionsWithObjectProps): DefineComponent, ExtractDefaultPropTypes, I, II, S, Options>; + + type AsyncComponentResolveResult = T | { + default: T; +@@ -1196,7 +1234,7 @@ export declare function defineProps(props: Pr + [key in PropNames]?: any; + }>>; + export declare function defineProps(props: PP): Prettify>>; +-export declare function defineProps(): DefineProps>; ++export declare function defineProps(): DefineProps, BooleanKey>; + type DefineProps = Readonly & { + readonly [K in BKeys]-?: boolean; + }; +@@ -1319,8 +1357,8 @@ type InferDefaults = { + }; + type NativeType = null | number | string | boolean | symbol | Function; + type InferDefault = ((props: P) => T & {}) | (T extends NativeType ? T : never); +-type PropsWithDefaults, BKeys extends keyof T> = Omit & { +- [K in keyof Defaults]-?: K extends keyof T ? Defaults[K] extends undefined ? T[K] : NotUndefined : never; ++type PropsWithDefaults, BKeys extends keyof T> = Readonly> & { ++ readonly [K in keyof Defaults]-?: K extends keyof T ? Defaults[K] extends undefined ? T[K] : NotUndefined : never; + } & { + readonly [K in BKeys]-?: K extends keyof Defaults ? Defaults[K] extends undefined ? boolean | undefined : boolean : boolean; + }; +@@ -1374,7 +1412,6 @@ export declare function h(type: typeof Teleport, props: RawProps & TeleportProps + export declare function h(type: typeof Suspense, children?: RawChildren): VNode; + export declare function h(type: typeof Suspense, props?: (RawProps & SuspenseProps) | null, children?: RawChildren | RawSlots): VNode; + export declare function h = {}>(type: FunctionalComponent, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode; +-export declare function h(type: Component, children?: RawChildren): VNode; + export declare function h

(type: ConcreteComponent | string, children?: RawChildren): VNode; + export declare function h

(type: ConcreteComponent

| string, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren): VNode; + export declare function h

(type: Component

, props?: (RawProps & P) | null, children?: RawChildren | RawSlots): VNode; +@@ -1383,8 +1420,10 @@ export declare function h(type: Constructor, children?: RawChildren): VNode; + export declare function h

(type: Constructor

, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode; + export declare function h(type: DefineComponent, children?: RawChildren): VNode; + export declare function h

(type: DefineComponent

, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode; +-export declare function h(type: string | Component, children?: RawChildren): VNode; +-export declare function h

(type: string | Component

, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode; ++export declare function h(type: VNode, children?: RawChildren): VNode; ++export declare function h

(type: VNode, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode; ++export declare function h(type: VNode | string | Constructor, children?: RawChildren): VNode; ++export declare function h

(type: VNode | string | Component

, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode; + + export declare const ssrContextKey: unique symbol; + export declare const useSSRContext: >() => T | undefined; +@@ -1437,6 +1476,62 @@ interface DevtoolsHook { + export declare let devtools: DevtoolsHook; + export declare function setDevtoolsHook(hook: DevtoolsHook, target: any): void; + ++export type ExtractComponentOptions = T extends { ++ [RawOptionsSymbol]: infer Options; ++} ? Options : T extends ComponentOptionsBase ? T : T extends { ++ props?: any; ++ emits?: any; ++ slots?: any; ++} ? T : T; ++export type ExtractComponentProp = T extends { ++ props: infer P; ++} ? P : T extends (props: infer P) => any ? P : T extends { ++ new (): { ++ $props: infer P; ++ }; ++} ? P : {}; ++export type ExtractComponentSlots = T extends ComponentOptionsBase ? S : T extends { ++ slots: infer S; ++} ? S : T extends { ++ slots: infer S extends Slots; ++} ? S : T extends (props: any, opts: { ++ slots: infer S; ++}) => any ? S : T extends { ++ new (): { ++ $slots: infer S extends Slots; ++ }; ++} ? S : {}; ++export type ExtractComponentEmits = T extends ComponentOptionsBase ? E : T extends { ++ emits: infer E; ++} ? E : T extends { ++ emits: infer E extends EmitsOptions; ++} ? E : T extends (props: any, opts: { ++ emits: infer E extends EmitsOptions; ++}) => any ? E : T extends { ++ $options: infer Options; ++} ? Options extends { ++ emits: infer E; ++} ? E : {} : {}; ++type ResolveMixin = [T] extends [ ++ Readonly> ++] ? IntersectionMixin & IntersectionMixin : {}; ++export type ComponentPropsWithDefaultOptional = ExtractDefaultPropTypes> extends infer Defaults ? Partial & Omit, keyof Defaults> : {}; ++type ResolveMixinProps = UnwrapMixinsType, 'P'>; ++export type ComponentProps = (excludeEmits extends false ? ExtractComponentEmits extends infer E ? E extends EmitsOptions ? EmitsToProps : unknown : unknown : {}) & (T extends { ++ $props: infer P; ++} ? P : (ExtractComponentProp extends infer P ? P extends Readonly> ? [V] extends [string] ? Readonly<{ ++ [key in V]?: any; ++}> : {} : P extends ComponentPropsOptions ? ExtractPropTypes

: P : {}) & (T extends { ++ props: any; ++} ? ResolveMixinProps> : {})); ++export type ComponentSlots = ExtractComponentSlots extends infer S ? { ++ [K in keyof S]: S[K] extends Slot ? (arg: V) => VNode : never; ++} : {}; ++export type ComponentEmits = ExtractComponentEmits extends infer E ? {} extends E ? () => void : EmitFn : () => void; ++export type ComponentInstance = T extends { ++ new (): ComponentPublicInstance; ++} ? InstanceType : T extends FunctionalComponent ? ComponentPublicInstance : T extends ComponentPublicInstanceConstructor ? InstanceType : T extends Component ? ComponentPublicInstance : never; ++ + type HMRComponent = ComponentOptions | ClassComponent; + export interface HMRRuntime { + createRecord: typeof createRecord; +@@ -1568,12 +1663,12 @@ interface LegacyPublicProperties { + */ + export type CompatVue = Pick & { + configureCompat: typeof configureCompat; +- new (options?: ComponentOptions): LegacyPublicInstance; ++ new (options?: ComponentOptionsCompat): LegacyPublicInstance; + version: string; + config: AppConfig & LegacyConfig; + nextTick: typeof nextTick; + use(plugin: Plugin, ...options: any[]): CompatVue; +- mixin(mixin: ComponentOptions): CompatVue; ++ mixin(mixin: ComponentOptionsCompat): CompatVue; + component(name: string): Component | undefined; + component(name: string, component: Component): CompatVue; + directive(name: string): Directive | undefined; +@@ -1582,7 +1677,7 @@ export type CompatVue = Pick & { + /** + * @deprecated Vue 3 no longer supports extending constructors. + */ +- extend: (options?: ComponentOptions) => CompatVue; ++ extend: (options?: ComponentOptionsCompat) => CompatVue; + /** + * @deprecated Vue 3 no longer needs set() for adding new properties. + */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 88d1b128d..dd2334268 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,11 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +patchedDependencies: + '@vue/runtime-core@3.3.8': + hash: o42dfj7r2ekysvvziyqw2shp2e + path: patches/@vue__runtime-core@3.3.8.patch + dependencies: js-beautify: specifier: ^1.14.9 @@ -1643,17 +1648,18 @@ packages: '@vue/shared': 3.3.8 dev: true - /@vue/runtime-core@3.3.8: + /@vue/runtime-core@3.3.8(patch_hash=o42dfj7r2ekysvvziyqw2shp2e): resolution: {integrity: sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==} dependencies: '@vue/reactivity': 3.3.8 '@vue/shared': 3.3.8 dev: true + patched: true /@vue/runtime-dom@3.3.8: resolution: {integrity: sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==} dependencies: - '@vue/runtime-core': 3.3.8 + '@vue/runtime-core': 3.3.8(patch_hash=o42dfj7r2ekysvvziyqw2shp2e) '@vue/shared': 3.3.8 csstype: 3.1.2 dev: true diff --git a/test-dts/tsconfig.tsd.json b/test-dts/tsconfig.tsd.json index f10ca8eb3..10a780a5c 100644 --- a/test-dts/tsconfig.tsd.json +++ b/test-dts/tsconfig.tsd.json @@ -3,14 +3,9 @@ "compilerOptions": { "noEmit": false, "skipLibCheck": true, - "experimentalDecorators": true, - "strictNullChecks": false + "experimentalDecorators": true + // "strictNullChecks": false }, - "exclude": [ - "../src", - ], - "include": [ - "../dist", - "../test-dts" - ] + "exclude": ["../src"], + "include": ["../dist", "../test-dts"] } From f4934bf4f89ba401d2e3cf2987c37f2bdde15264 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Thu, 16 Nov 2023 11:44:09 +0000 Subject: [PATCH 06/15] fix --- src/vueWrapper.ts | 26 +++++--------------------- src/wrapperFactory.ts | 2 +- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index ed8c09187..de190b5ac 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -3,8 +3,7 @@ import { App, ComponentPublicInstance, VNode, - ExtractComponentEmits, - ComponentCustomProperties + ExtractComponentEmits } from 'vue' import { config } from './config' @@ -95,23 +94,9 @@ type ResolveEmitRecord = ExtractComponentEmits extends infer E } : never -declare const aaa: keyof Omit< - ComponentPublicInstance, - keyof ComponentCustomProperties -> - -// type BetterKeys = keyof Omit< -// ComponentPublicInstance, -// keyof ComponentCustomProperties -// > -// export type ComponentInstance = { -// [K in keyof ComponentPublicInstance]?: any -// } & Record - export class VueWrapper< - T extends Omit & { - $emit: any - } = ComponentPublicInstance + VM = unknown, + T extends ComponentPublicInstance = ComponentPublicInstance & VM > extends BaseWrapper { private readonly componentVM: T private readonly rootVM: ComponentPublicInstance | undefined | null @@ -251,7 +236,6 @@ export class VueWrapper< get vm(): T { return this.componentVM } - props(): T['$props'] props( selector: Selector @@ -264,9 +248,9 @@ export class VueWrapper< } emitted(): ResolveEmitRecord - emitted>( + emitted>( eventName: E - ): undefined | ResolveEmitRecord[E] + ): undefined | ResolveEmitRecord[E] emitted(eventName?: string) { return emitted(this.vm, eventName) } diff --git a/src/wrapperFactory.ts b/src/wrapperFactory.ts index 429773e30..6eea52caa 100644 --- a/src/wrapperFactory.ts +++ b/src/wrapperFactory.ts @@ -1,4 +1,4 @@ -import { ComponentPublicInstance, App } from 'vue' +import { App, ComponentPublicInstance } from 'vue' import type { DOMWrapper as DOMWrapperType } from './domWrapper' import type { VueWrapper as VueWrapperType } from './vueWrapper' From 1f1c3e633289205b2235baa392bf37fee3bdf968 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Thu, 16 Nov 2023 11:58:37 +0000 Subject: [PATCH 07/15] ... --- src/vueWrapper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index de190b5ac..8790af8a4 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -88,8 +88,8 @@ type ResolveEmitRecord = ExtractComponentEmits extends infer E ? Args extends { length: 0 } ? void : Args extends { length: 1 } - ? Args[0] - : Args + ? Args[0] + : Args : void)[] } : never From 43160322a56631c9aea019bff7f5eaee0b37272a Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Thu, 16 Nov 2023 12:23:38 +0000 Subject: [PATCH 08/15] fixing emit type errors --- src/vueWrapper.ts | 11 ++++++++--- tests/emit.spec.ts | 4 ++++ tests/features/teleport.spec.ts | 2 ++ tests/trigger.spec.ts | 1 + 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 8790af8a4..3aea3a33d 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -88,8 +88,8 @@ type ResolveEmitRecord = ExtractComponentEmits extends infer E ? Args extends { length: 0 } ? void : Args extends { length: 1 } - ? Args[0] - : Args + ? Args[0] + : Args : void)[] } : never @@ -247,10 +247,15 @@ export class VueWrapper< return selector ? props[selector] : props } - emitted(): ResolveEmitRecord + emitted(): ResolveEmitRecord extends infer E + ? {} extends E + ? Record + : E + : never emitted>( eventName: E ): undefined | ResolveEmitRecord[E] + emitted(eventName: string): undefined | any[] emitted(eventName?: string) { return emitted(this.vm, eventName) } diff --git a/tests/emit.spec.ts b/tests/emit.spec.ts index ffc4c6b4a..06eaab250 100644 --- a/tests/emit.spec.ts +++ b/tests/emit.spec.ts @@ -158,6 +158,7 @@ describe('emitted', () => { // Parent should emit custom event 'hello' but not 'hi' expect(wrapper.emitted().hello[0]).toEqual(['foo', 'bar']) + // @ts-expect-error `hi` is not a valid event expect(wrapper.emitted().hi).toEqual(undefined) // Child should emit custom event 'hi' expect(childWrapper.emitted().hi[0]).toEqual(['foo', 'bar']) @@ -165,6 +166,7 @@ describe('emitted', () => { // Additional events should accumulate in the same format wrapper.find('button').trigger('click') expect(wrapper.emitted().hello[1]).toEqual(['foo', 'bar']) + // @ts-expect-error `hi` is not a valid event expect(wrapper.emitted().hi).toEqual(undefined) expect(childWrapper.emitted().hi[1]).toEqual(['foo', 'bar']) }) @@ -340,6 +342,7 @@ describe('emitted', () => { const wrapper = mount(EmitsEventSFC) await wrapper.trigger('click') + // @ts-expect-error `click` is not defined expect(wrapper.emitted().click).toHaveLength(1) expect(wrapper.emitted().bar).toHaveLength(2) expect(wrapper.emitted().bar[0]).toEqual(['mounted']) @@ -350,6 +353,7 @@ describe('emitted', () => { const wrapper = mount(EmitsEventScriptSetup) await wrapper.trigger('click') + // @ts-expect-error `click` is not a valid event expect(wrapper.emitted().click).toHaveLength(1) expect(wrapper.emitted().bar).toHaveLength(2) expect(wrapper.emitted().bar[0]).toEqual(['mounted']) diff --git a/tests/features/teleport.spec.ts b/tests/features/teleport.spec.ts index 651495b32..6c71783bf 100644 --- a/tests/features/teleport.spec.ts +++ b/tests/features/teleport.spec.ts @@ -142,6 +142,8 @@ describe('teleport', () => { const withProps = wrapper.getComponent(EmitsEvent) withProps.trigger('click') + withProps.vm.$emit('greet') + expect(withProps.emitted().greet[0]).toEqual(['Hey!']) }) diff --git a/tests/trigger.spec.ts b/tests/trigger.spec.ts index 8293a3ca8..6b4173e1a 100644 --- a/tests/trigger.spec.ts +++ b/tests/trigger.spec.ts @@ -349,6 +349,7 @@ describe('trigger', () => { it('dispatches event', async () => { const Comp = defineComponent({ + emits: ['enter'], template: ` Date: Thu, 16 Nov 2023 15:31:52 +0000 Subject: [PATCH 09/15] some updates --- patches/@vue__runtime-core@3.3.8.patch | 40 ++++++++-- pnpm-lock.yaml | 6 +- src/mount.ts | 76 ++++++++++++++++++- .../stubComponentsTransformer.ts | 2 +- tests/setData.spec.ts | 24 +++--- tests/setProps.spec.ts | 12 +-- 6 files changed, 129 insertions(+), 31 deletions(-) diff --git a/patches/@vue__runtime-core@3.3.8.patch b/patches/@vue__runtime-core@3.3.8.patch index 2f87f00d0..7501c6f26 100644 --- a/patches/@vue__runtime-core@3.3.8.patch +++ b/patches/@vue__runtime-core@3.3.8.patch @@ -1,5 +1,5 @@ diff --git a/dist/runtime-core.d.ts b/dist/runtime-core.d.ts -index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..93ad7c6ac81064255901ac6319a31a6853ac491e 100644 +index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e8666db95 100644 --- a/dist/runtime-core.d.ts +++ b/dist/runtime-core.d.ts @@ -1,7 +1,7 @@ @@ -64,6 +64,15 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..93ad7c6ac81064255901ac6319a31a68 export type Prop = PropOptions | PropType; type DefaultFactory = (props: Data) => T | null | undefined; interface PropOptions { +@@ -467,7 +483,7 @@ export type ExtractPublicPropTypes = { + } & { + [K in keyof Pick>]?: InferPropType; + }; +-export type ExtractDefaultPropTypes = O extends object ? { ++export type ExtractDefaultPropTypes = [O] extends [object] ? { + [K in keyof Pick>]: InferPropType; + } : {}; + @@ -514,6 +530,15 @@ export type DirectiveArguments = Array<[Directive | undefined] | [Directive | un */ export declare function withDirectives(vnode: T, directives: DirectiveArguments): T; @@ -124,6 +133,15 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..93ad7c6ac81064255901ac6319a31a68 __isTeleport: boolean; process(n1: TeleportVNode | null, n2: TeleportVNode, container: RendererElement, anchor: RendererNode | null, parentComponent: ComponentInternalInstance | null, parentSuspense: SuspenseBoundary | null, isSVG: boolean, slotScopeIds: string[] | null, optimized: boolean, internals: RendererInternals): void; remove(vnode: VNode, parentComponent: ComponentInternalInstance | null, parentSuspense: SuspenseBoundary | null, optimized: boolean, { um: unmount, o: { remove: hostRemove } }: RendererInternals, doRemove: boolean): void; +@@ -822,7 +848,7 @@ declare const TeleportImpl: { + }; + declare const enum TeleportMoveTypes { + TARGET_CHANGE = 0, +- TOGGLE = 1, ++ TOGGLE = 1,// enable / disable + REORDER = 2 + } + declare function moveTeleport(vnode: VNode, container: RendererElement, parentAnchor: RendererNode | null, { o: { insert }, m: move }: RendererInternals, moveType?: TeleportMoveTypes): void; @@ -883,7 +909,7 @@ export type VNodeProps = { onVnodeBeforeUnmount?: VNodeMountHook | VNodeMountHook[]; onVnodeUnmounted?: VNodeMountHook | VNodeMountHook[]; @@ -225,7 +243,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..93ad7c6ac81064255901ac6319a31a68 export declare const ssrContextKey: unique symbol; export declare const useSSRContext: >() => T | undefined; -@@ -1437,6 +1476,62 @@ interface DevtoolsHook { +@@ -1437,6 +1476,70 @@ interface DevtoolsHook { export declare let devtools: DevtoolsHook; export declare function setDevtoolsHook(hook: DevtoolsHook, target: any): void; @@ -268,7 +286,13 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..93ad7c6ac81064255901ac6319a31a68 +type ResolveMixin = [T] extends [ + Readonly> +] ? IntersectionMixin & IntersectionMixin : {}; -+export type ComponentPropsWithDefaultOptional = ExtractDefaultPropTypes> extends infer Defaults ? Partial & Omit, keyof Defaults> : {}; ++export type ComponentPropsWithDefaultOptional = ((T extends { ++ props: infer P; ++} ? [P] extends [Array] ? [PA] extends [string] ? { ++ [key in PA]?: any; ++} : never : P : T) extends infer Props ? ExtractDefaultPropTypes extends infer Defaults ? Partial & Omit, keyof Defaults> : {} : {}) & (T extends { ++ props: any; ++} ? ResolveMixinProps> : ResolveMixinProps); +type ResolveMixinProps = UnwrapMixinsType, 'P'>; +export type ComponentProps = (excludeEmits extends false ? ExtractComponentEmits extends infer E ? E extends EmitsOptions ? EmitsToProps : unknown : unknown : {}) & (T extends { + $props: infer P; @@ -276,19 +300,21 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..93ad7c6ac81064255901ac6319a31a68 + [key in V]?: any; +}> : {} : P extends ComponentPropsOptions ? ExtractPropTypes

: P : {}) & (T extends { + props: any; -+} ? ResolveMixinProps> : {})); ++} ? ResolveMixinProps> : ResolveMixinProps)); +export type ComponentSlots = ExtractComponentSlots extends infer S ? { + [K in keyof S]: S[K] extends Slot ? (arg: V) => VNode : never; +} : {}; +export type ComponentEmits = ExtractComponentEmits extends infer E ? {} extends E ? () => void : EmitFn : () => void; +export type ComponentInstance = T extends { + new (): ComponentPublicInstance; -+} ? InstanceType : T extends FunctionalComponent ? ComponentPublicInstance : T extends ComponentPublicInstanceConstructor ? InstanceType : T extends Component ? ComponentPublicInstance : never; ++} ? InstanceType : T extends FunctionalComponent ? ComponentPublicInstance : T extends ComponentPublicInstanceConstructor ? InstanceType : T extends ComponentDefineOptions ? InstanceType ? PA : P : Props, RawBindings, D, C, M, Mixin, Extends, E, EE, I, II, S, Options>>> : T extends Component ? ComponentPublicInstance : never; + type HMRComponent = ComponentOptions | ClassComponent; export interface HMRRuntime { createRecord: typeof createRecord; -@@ -1568,12 +1663,12 @@ interface LegacyPublicProperties { +@@ -1568,12 +1671,12 @@ interface LegacyPublicProperties { */ export type CompatVue = Pick & { configureCompat: typeof configureCompat; @@ -303,7 +329,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..93ad7c6ac81064255901ac6319a31a68 component(name: string): Component | undefined; component(name: string, component: Component): CompatVue; directive(name: string): Directive | undefined; -@@ -1582,7 +1677,7 @@ export type CompatVue = Pick & { +@@ -1582,7 +1685,7 @@ export type CompatVue = Pick & { /** * @deprecated Vue 3 no longer supports extending constructors. */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37ed596c3..5b206be5f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: patchedDependencies: '@vue/runtime-core@3.3.8': - hash: o42dfj7r2ekysvvziyqw2shp2e + hash: 4orkj7obj2wcx2tgwse3zhn7s4 path: patches/@vue__runtime-core@3.3.8.patch dependencies: @@ -1648,7 +1648,7 @@ packages: '@vue/shared': 3.3.8 dev: true - /@vue/runtime-core@3.3.8(patch_hash=o42dfj7r2ekysvvziyqw2shp2e): + /@vue/runtime-core@3.3.8(patch_hash=4orkj7obj2wcx2tgwse3zhn7s4): resolution: {integrity: sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==} dependencies: '@vue/reactivity': 3.3.8 @@ -1659,7 +1659,7 @@ packages: /@vue/runtime-dom@3.3.8: resolution: {integrity: sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==} dependencies: - '@vue/runtime-core': 3.3.8(patch_hash=o42dfj7r2ekysvvziyqw2shp2e) + '@vue/runtime-core': 3.3.8(patch_hash=4orkj7obj2wcx2tgwse3zhn7s4) '@vue/shared': 3.3.8 csstype: 3.1.2 dev: true diff --git a/src/mount.ts b/src/mount.ts index 8dc47ac7e..a35fb5d69 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -2,7 +2,14 @@ import { ComponentPublicInstance, DefineComponent, VNode, - ComponentInstance + ComponentInstance, + ComputedOptions, + MethodOptions, + ComponentOptionsMixin, + EmitsOptions, + ComponentInjectOptions, + SlotsType, + ComponentDefineOptions } from 'vue' import type { ComponentSlots } from 'vue-component-type-helpers' import { createInstance } from './createInstance' @@ -35,6 +42,71 @@ export type ComponentMountingOptions = Omit< } } & Record +// export function mount< +// Props = never, +// RawBindings = {}, +// D = {}, +// C extends ComputedOptions = {}, +// M extends MethodOptions = {}, +// Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, +// Extends extends ComponentOptionsMixin = ComponentOptionsMixin, +// E extends EmitsOptions = {}, +// EE extends string = string, +// I extends ComponentInjectOptions = {}, +// II extends string = string, +// S extends SlotsType = {}, +// Options = {} +// >( +// originalComponent: ComponentDefineOptions< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S, +// Options +// >, +// options?: ComponentMountingOptions< +// ComponentDefineOptions< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S, +// Options +// >, +// ComponentPropsWithDefaultOptional< +// ComponentDefineOptions< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S, +// Options +// > +// > +// > +// ): { props: Props } // defineComponent export function mount< T extends DefineComponent< @@ -49,7 +121,7 @@ export function mount< any, any >, - PropsOrOptions + PropsOrOptions extends object >( originalComponent: T, options?: ComponentMountingOptions> diff --git a/src/vnodeTransformers/stubComponentsTransformer.ts b/src/vnodeTransformers/stubComponentsTransformer.ts index 10220f4b6..3651d2bc3 100644 --- a/src/vnodeTransformers/stubComponentsTransformer.ts +++ b/src/vnodeTransformers/stubComponentsTransformer.ts @@ -32,7 +32,7 @@ import { registerStub } from '../stubs' export type CustomCreateStub = (params: { name: string - component: ConcreteComponent + component: Component registerStub: (config: { source: Component; stub: Component }) => void }) => ConcreteComponent diff --git a/tests/setData.spec.ts b/tests/setData.spec.ts index 6e0edb35b..93955bf07 100644 --- a/tests/setData.spec.ts +++ b/tests/setData.spec.ts @@ -189,20 +189,18 @@ describe('setData', () => { }) it('should keep Date object on setData', async () => { - const wrapper = mount( - defineComponent({ - template: '

', - props: { modelValue: Date }, - data() { - return { value: this.modelValue } - } - }), - { - props: { - modelValue: new Date('2022-08-10T12:15:54Z') - } + const comp = defineComponent({ + template: '
', + props: { modelValue: Date }, + data() { + return { value: this.modelValue } } - ) + }) + const wrapper = mount(comp, { + props: { + modelValue: new Date('2022-08-10T12:15:54Z') + } + }) expect(wrapper.vm.value).toBeInstanceOf(Date) expect(wrapper.vm.value!.toISOString()).toBe('2022-08-10T12:15:54.000Z') diff --git a/tests/setProps.spec.ts b/tests/setProps.spec.ts index d58a7c7d7..f736d0001 100644 --- a/tests/setProps.spec.ts +++ b/tests/setProps.spec.ts @@ -23,7 +23,7 @@ describe('setProps', () => { it('updates a function prop', async () => { const Foo = { - props: ['obj'], + props: ['obj'] as ['obj'], template: `
foo
@@ -37,15 +37,15 @@ describe('setProps', () => { } } }) - expect(wrapper.html()).toContain('foo') + expect(wrapper.html()).toContain('foo') await wrapper.setProps({ obj: { foo: () => false } }) expect(wrapper.html()).not.toContain('foo') }) it('sets component props, and updates DOM when props were not initially passed', async () => { const Foo = { - props: ['foo'], + props: ['foo'] as ['foo'], template: `
{{ foo }}
` } @@ -126,11 +126,11 @@ describe('setProps', () => { it('allows using only on mounted component', async () => { const Foo = { name: 'Foo', - props: ['foo'], + props: ['foo'] as ['foo'], template: '
{{ foo }}
' } const Baz = { - props: ['baz'], + props: ['baz'] as ['baz'], template: '
', components: { Foo } } @@ -141,6 +141,8 @@ describe('setProps', () => { } }) const FooResult = wrapper.findComponent({ name: 'Foo' }) + + // @ts-expect-error not valid prop expect(() => FooResult.setProps({ baz: 'bin' })).toThrowError( 'You can only use setProps on your mounted component' ) From c7242ef8a275cadddc2e9aef04bb788da8f8f9e1 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Sat, 18 Nov 2023 11:26:17 +0000 Subject: [PATCH 10/15] updated --- patches/@vue__runtime-core@3.3.8.patch | 151 ++++++++++++++++++------- pnpm-lock.yaml | 6 +- src/baseWrapper.ts | 12 +- src/mount.ts | 127 +++++++++++++++++---- test-dts/mount.d-test.ts | 6 +- test-dts/shallowMount.d-test.ts | 4 +- test-dts/wrapper.d-test.ts | 54 ++++++--- 7 files changed, 272 insertions(+), 88 deletions(-) diff --git a/patches/@vue__runtime-core@3.3.8.patch b/patches/@vue__runtime-core@3.3.8.patch index 7501c6f26..7dfc02e59 100644 --- a/patches/@vue__runtime-core@3.3.8.patch +++ b/patches/@vue__runtime-core@3.3.8.patch @@ -1,5 +1,5 @@ diff --git a/dist/runtime-core.d.ts b/dist/runtime-core.d.ts -index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e8666db95 100644 +index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..a4377187d514a0663c3a35c073e794b4cfd98d76 100644 --- a/dist/runtime-core.d.ts +++ b/dist/runtime-core.d.ts @@ -1,7 +1,7 @@ @@ -11,7 +11,16 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e export declare const computed: typeof computed$1; -@@ -101,17 +101,32 @@ type ExtractMixin = { +@@ -62,7 +62,7 @@ type EmitsToProps = T extends string[] ? { + } : T extends ObjectEmitsOptions ? { + [K in string & `on${Capitalize}`]?: K extends `on${infer C}` ? T[Uncapitalize] extends null ? (...args: any[]) => any : (...args: T[Uncapitalize] extends (...args: infer P) => any ? P : never) => any : never; + } : {}; +-type EmitFn = Options extends Array ? (event: V, ...args: any[]) => void : {} extends Options ? (event: string, ...args: any[]) => void : UnionToIntersection<{ ++type EmitFn = Options extends Array ? (event: V, ...args: any[]) => void : {} extends Options ? (event: any, ...args: any[]) => any | ((event: string, ...args: any[]) => void) : UnionToIntersection<{ + [key in Event]: Options[key] extends (...args: infer Args) => any ? (event: key, ...args: Args) => void : (event: key, ...args: any[]) => void; + }[Event]>; + +@@ -101,20 +101,39 @@ type ExtractMixin = { type IntersectionMixin = IsDefaultMixinComponent extends true ? OptionTypesType : UnionToIntersection>; type UnwrapMixinsType = T extends OptionTypesType ? T[Type] : never; type EnsureNonVoid = T extends void ? {} : T; @@ -39,6 +48,10 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e }; -export type CreateComponentPublicInstance

& IntersectionMixin, PublicP = UnwrapMixinsType & EnsureNonVoid

, PublicB = UnwrapMixinsType & EnsureNonVoid, PublicD = UnwrapMixinsType & EnsureNonVoid, PublicC extends ComputedOptions = UnwrapMixinsType & EnsureNonVoid, PublicM extends MethodOptions = UnwrapMixinsType & EnsureNonVoid, PublicDefaults = UnwrapMixinsType & EnsureNonVoid> = ComponentPublicInstance, I, S>; +export type CreateComponentPublicInstance

, PublicMixin = IntersectionMixin & IntersectionMixin, PublicP = UnwrapMixinsType & EnsureNonVoid

, PublicB = UnwrapMixinsType & EnsureNonVoid, PublicD = UnwrapMixinsType & EnsureNonVoid, PublicC extends ComputedOptions = UnwrapMixinsType & EnsureNonVoid, PublicM extends MethodOptions = UnwrapMixinsType & EnsureNonVoid, PublicDefaults = UnwrapMixinsType & EnsureNonVoid> = ComponentPublicInstance; ++/** ++ * Resolves props ++ */ ++type ComponentPropsWithDefault = MakeDefaultsOptional extends true ? Partial & Omit & PublicProps, keyof Defaults> : Prettify

& PublicProps; export type ComponentPublicInstance

= { $: ComponentInternalInstance; $data: D; - $props: MakeDefaultsOptional extends true ? Partial & Omit & PublicProps, keyof Defaults> : Prettify

& PublicProps; -@@ -126,7 +141,7 @@ C extends ComputedOptions = {}, M extends MethodOptions = {}, E extends EmitsOpt +- $props: MakeDefaultsOptional extends true ? Partial & Omit & PublicProps, keyof Defaults> : Prettify

& PublicProps; ++ $props: ComponentPropsWithDefault; + $attrs: Data; + $refs: Data; + $slots: UnwrapSlotsType; +@@ -126,7 +145,7 @@ C extends ComputedOptions = {}, M extends MethodOptions = {}, E extends EmitsOpt $forceUpdate: () => void; $nextTick: typeof nextTick; $watch any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R]) => any : (...args: any) => any, options?: WatchOptions): WatchStopHandle; @@ -56,7 +73,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e declare const enum LifecycleHooks { BEFORE_CREATE = "bc", -@@ -383,6 +398,7 @@ export type ComponentPropsOptions

= ComponentObjectPropsOptions

| s +@@ -383,6 +402,7 @@ export type ComponentPropsOptions

= ComponentObjectPropsOptions

| s export type ComponentObjectPropsOptions

= { [K in keyof P]: Prop | null; }; @@ -64,7 +81,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e export type Prop = PropOptions | PropType; type DefaultFactory = (props: Data) => T | null | undefined; interface PropOptions { -@@ -467,7 +483,7 @@ export type ExtractPublicPropTypes = { +@@ -467,7 +487,7 @@ export type ExtractPublicPropTypes = { } & { [K in keyof Pick>]?: InferPropType; }; @@ -73,7 +90,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e [K in keyof Pick>]: InferPropType; } : {}; -@@ -514,6 +530,15 @@ export type DirectiveArguments = Array<[Directive | undefined] | [Directive | un +@@ -514,6 +534,15 @@ export type DirectiveArguments = Array<[Directive | undefined] | [Directive | un */ export declare function withDirectives(vnode: T, directives: DirectiveArguments): T; @@ -89,7 +106,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e export declare const enum DeprecationTypes { GLOBAL_MOUNT = "GLOBAL_MOUNT", GLOBAL_MOUNT_CONTAINER = "GLOBAL_MOUNT_CONTAINER", -@@ -610,19 +635,19 @@ export interface RuntimeCompilerOptions { +@@ -610,19 +639,19 @@ export interface RuntimeCompilerOptions { comments?: boolean; delimiters?: [string, string]; } @@ -116,7 +133,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e export type ComputedOptions = Record | WritableComputedOptions>; export interface MethodOptions { [key: string]: Function; -@@ -652,7 +677,7 @@ type InjectToObject = T extends string[] ? { +@@ -652,7 +681,7 @@ type InjectToObject = T extends string[] ? { } : never; interface LegacyOptions { compatConfig?: CompatConfig; @@ -125,7 +142,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e data?: (this: CreateComponentPublicInstance, vm: CreateComponentPublicInstance) => D; computed?: C; methods?: M; -@@ -814,6 +839,7 @@ export interface TeleportProps { +@@ -814,6 +843,7 @@ export interface TeleportProps { disabled?: boolean; } declare const TeleportImpl: { @@ -133,16 +150,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e __isTeleport: boolean; process(n1: TeleportVNode | null, n2: TeleportVNode, container: RendererElement, anchor: RendererNode | null, parentComponent: ComponentInternalInstance | null, parentSuspense: SuspenseBoundary | null, isSVG: boolean, slotScopeIds: string[] | null, optimized: boolean, internals: RendererInternals): void; remove(vnode: VNode, parentComponent: ComponentInternalInstance | null, parentSuspense: SuspenseBoundary | null, optimized: boolean, { um: unmount, o: { remove: hostRemove } }: RendererInternals, doRemove: boolean): void; -@@ -822,7 +848,7 @@ declare const TeleportImpl: { - }; - declare const enum TeleportMoveTypes { - TARGET_CHANGE = 0, -- TOGGLE = 1, -+ TOGGLE = 1,// enable / disable - REORDER = 2 - } - declare function moveTeleport(vnode: VNode, container: RendererElement, parentAnchor: RendererNode | null, { o: { insert }, m: move }: RendererInternals, moveType?: TeleportMoveTypes): void; -@@ -883,7 +909,7 @@ export type VNodeProps = { +@@ -883,7 +913,7 @@ export type VNodeProps = { onVnodeBeforeUnmount?: VNodeMountHook | VNodeMountHook[]; onVnodeUnmounted?: VNodeMountHook | VNodeMountHook[]; }; @@ -151,7 +159,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e export type VNodeArrayChildren = Array; export type VNodeChild = VNodeChildAtom | VNodeArrayChildren; export type VNodeNormalizedChildren = string | VNodeArrayChildren | RawSlots | null; -@@ -1037,7 +1063,7 @@ interface ClassComponent { +@@ -1037,7 +1067,7 @@ interface ClassComponent { * values, e.g. checking if its a function or not. This is mostly for internal * implementation code. */ @@ -160,7 +168,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e /** * A type used in public APIs where a component type is expected. * The constructor type is an artificial type returned by defineComponent(). -@@ -1123,9 +1149,21 @@ export declare function watch, Immediate e +@@ -1123,9 +1153,24 @@ export declare function watch, Immediate e export declare function watch = false>(source: WatchSource, cb: WatchCallback, options?: WatchOptions): WatchStopHandle; export declare function watch = false>(source: T, cb: WatchCallback, options?: WatchOptions): WatchStopHandle; @@ -177,15 +185,18 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e +} & Omit & { + [RawOptionsSymbol]: Options; +} & PP; -+export type ComponentDefineOptions = (Options & { ++export type DefineComponentOptions = (Options & { + props?: [Props] extends [never] ? string[] : [Props] extends [string] ? Array : Props; +} & ([Props] extends [string] ? ComponentOptionsWithArrayProps : [Props] extends [undefined] ? { + props?: undefined; +} & ComponentOptionsWithoutProps<{}, RawBindings, D, C, M, Mixin, Extends, E, EE, I, II, S> : Props extends ComponentObjectPropsOptions ? ComponentOptionsWithObjectProps : ComponentOptions & EmitsToProps>, RawBindings, D, C, M, Mixin, Extends, E, I, S>)) | (((props: Props, ctx: SetupContext) => RenderFunction | Promise) & Options); ++export type DefineComponentFromOptions = DefineComponent<[ ++ Props ++] extends [string] ? Props[] : undefined extends Props ? {} : Props extends never[] ? string[] : Props, RawBindings, D, C, M, Mixin, Extends, E, EE, PublicProps$1, ResolveProps, ExtractDefaultPropTypes, I, II, S, Options>; export declare function defineComponent, E extends EmitsOptions = {}, EE extends string = string, S extends SlotsType = {}>(setup: (props: Props, ctx: SetupContext) => RenderFunction | Promise, options?: Pick & { props?: (keyof Props)[]; emits?: E | EE[]; -@@ -1136,11 +1174,11 @@ export declare function defineComponent, E ext +@@ -1136,11 +1181,9 @@ export declare function defineComponent, E ext emits?: E | EE[]; slots?: S; }): (props: Props & EmitsToProps) => any; @@ -195,14 +206,12 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e -}>>(options: ComponentOptionsWithArrayProps): DefineComponent, ExtractDefaultPropTypes, S>; -export declare function defineComponent, RawBindings, D, C extends ComputedOptions = {}, M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = {}, EE extends string = string, S extends SlotsType = {}, I extends ComponentInjectOptions = {}, II extends string = string>(options: ComponentOptionsWithObjectProps): DefineComponent, ExtractDefaultPropTypes, S>; +export declare function defineComponent(options: Options & ComponentOptionsWithoutProps): DefineComponent, ExtractDefaultPropTypes, I, II, S, Options>; -+export declare function defineComponent(options: ComponentDefineOptions): DefineComponent<[ -+ Props -+] extends [string] ? Props[] : undefined extends Props ? {} : Props extends never[] ? string[] : Props, RawBindings, D, C, M, Mixin, Extends, E, EE, PublicProps$1, ResolveProps, ExtractDefaultPropTypes, I, II, S, Options>; ++export declare function defineComponent(options: DefineComponentOptions): DefineComponentFromOptions; +export declare function defineComponent(options: Options & ComponentOptionsWithObjectProps): DefineComponent, ExtractDefaultPropTypes, I, II, S, Options>; type AsyncComponentResolveResult = T | { default: T; -@@ -1196,7 +1234,7 @@ export declare function defineProps(props: Pr +@@ -1196,7 +1239,7 @@ export declare function defineProps(props: Pr [key in PropNames]?: any; }>>; export declare function defineProps(props: PP): Prettify>>; @@ -211,7 +220,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e type DefineProps = Readonly & { readonly [K in BKeys]-?: boolean; }; -@@ -1319,8 +1357,8 @@ type InferDefaults = { +@@ -1319,8 +1362,8 @@ type InferDefaults = { }; type NativeType = null | number | string | boolean | symbol | Function; type InferDefault = ((props: P) => T & {}) | (T extends NativeType ? T : never); @@ -222,7 +231,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e } & { readonly [K in BKeys]-?: K extends keyof Defaults ? Defaults[K] extends undefined ? boolean | undefined : boolean : boolean; }; -@@ -1374,7 +1412,6 @@ export declare function h(type: typeof Teleport, props: RawProps & TeleportProps +@@ -1374,7 +1417,6 @@ export declare function h(type: typeof Teleport, props: RawProps & TeleportProps export declare function h(type: typeof Suspense, children?: RawChildren): VNode; export declare function h(type: typeof Suspense, props?: (RawProps & SuspenseProps) | null, children?: RawChildren | RawSlots): VNode; export declare function h = {}>(type: FunctionalComponent, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode; @@ -230,7 +239,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e export declare function h

(type: ConcreteComponent | string, children?: RawChildren): VNode; export declare function h

(type: ConcreteComponent

| string, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren): VNode; export declare function h

(type: Component

, props?: (RawProps & P) | null, children?: RawChildren | RawSlots): VNode; -@@ -1383,8 +1420,10 @@ export declare function h(type: Constructor, children?: RawChildren): VNode; +@@ -1383,8 +1425,10 @@ export declare function h(type: Constructor, children?: RawChildren): VNode; export declare function h

(type: Constructor

, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode; export declare function h(type: DefineComponent, children?: RawChildren): VNode; export declare function h

(type: DefineComponent

, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode; @@ -243,10 +252,13 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e export declare const ssrContextKey: unique symbol; export declare const useSSRContext: >() => T | undefined; -@@ -1437,6 +1476,70 @@ interface DevtoolsHook { +@@ -1437,6 +1481,128 @@ interface DevtoolsHook { export declare let devtools: DevtoolsHook; export declare function setDevtoolsHook(hook: DevtoolsHook, target: any): void; ++/** ++ * Extracts the component original options ++ */ +export type ExtractComponentOptions = T extends { + [RawOptionsSymbol]: infer Options; +} ? Options : T extends ComponentOptionsBase ? T : T extends { @@ -261,6 +273,9 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e + $props: infer P; + }; +} ? P : {}; ++/** ++ * Extracts the component slots as the component was created ++ */ +export type ExtractComponentSlots = T extends ComponentOptionsBase ? S : T extends { + slots: infer S; +} ? S : T extends { @@ -272,6 +287,9 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e + $slots: infer S extends Slots; + }; +} ? S : {}; ++/** ++ * Extracts the component emits as the component was created ++ */ +export type ExtractComponentEmits = T extends ComponentOptionsBase ? E : T extends { + emits: infer E; +} ? E : T extends { @@ -286,35 +304,84 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e +type ResolveMixin = [T] extends [ + Readonly> +] ? IntersectionMixin & IntersectionMixin : {}; -+export type ComponentPropsWithDefaultOptional = ((T extends { ++export type ObjectToComponentProps = T extends Record ? { ++ [K in keyof T]: { ++ type: PropType; ++ required: T[K] extends undefined ? false : true; ++ }; ++} : {}; ++/** ++ * Extracts Original props from options ++ */ ++export type ResolvePropsFromOptions = T extends { + props: infer P; -+} ? [P] extends [Array] ? [PA] extends [string] ? { -+ [key in PA]?: any; -+} : never : P : T) extends infer Props ? ExtractDefaultPropTypes extends infer Defaults ? Partial & Omit, keyof Defaults> : {} : {}) & (T extends { ++} ? [P] extends [Array] ? [PA] extends [string] ? ObjectToComponentProps> : never : P : T extends (props: infer P) => any ? ObjectToComponentProps

: T extends { ++ new (): { ++ $props: infer P; ++ }; ++} ? ObjectToComponentProps

: T; ++/** ++ * Get the Component props making the default optional ++ * Used mainly on the render component ++ */ ++export type ComponentPropsWithDefaultOptional = (ResolvePropsFromOptions extends infer Props ? ExtractDefaultPropTypes extends infer Defaults ? Partial & Omit, keyof Defaults> : {} : {}) & (T extends { + props: any; -+} ? ResolveMixinProps> : ResolveMixinProps); ++} ? ResolveMixinProps> : T extends ((...args: any) => any) | (abstract new (...args: any) => any) ? {} : ResolveMixinProps); +type ResolveMixinProps = UnwrapMixinsType, 'P'>; -+export type ComponentProps = (excludeEmits extends false ? ExtractComponentEmits extends infer E ? E extends EmitsOptions ? EmitsToProps : unknown : unknown : {}) & (T extends { ++/** ++ * Returns the emits as props ++ */ ++export type ComponentEmitsProps = ExtractComponentEmits extends infer E ? E extends EmitsOptions ? EmitsToProps : unknown : unknown; ++/** ++ * Returns runtime props definition for a component ++ * ++ * @see Include emits {@linkcode ComponentEmitsProps} ++ * @see Get the render props {@linkcode ComponentPropsWithDefaultOptional} ++ * ++ * @example ++ * ```ts ++ * import { Comp } from './Comp.vue' ++ * ++ * function useProps(): ComponentProps { ++ * // ... ++ * } ++ * ``` ++ */ ++export type ComponentProps = T extends { + $props: infer P; +} ? P : (ExtractComponentProp extends infer P ? P extends Readonly> ? [V] extends [string] ? Readonly<{ + [key in V]?: any; +}> : {} : P extends ComponentPropsOptions ? ExtractPropTypes

: P : {}) & (T extends { + props: any; -+} ? ResolveMixinProps> : ResolveMixinProps)); ++} ? ResolveMixinProps> : ResolveMixinProps); ++/** ++ * Returns runtime type for `slots` ++ */ +export type ComponentSlots = ExtractComponentSlots extends infer S ? { + [K in keyof S]: S[K] extends Slot ? (arg: V) => VNode : never; +} : {}; +export type ComponentEmits = ExtractComponentEmits extends infer E ? {} extends E ? () => void : EmitFn : () => void; ++/** ++ * Retrieves the component public instance ++ * ++ * @example ++ * ```ts ++ * const Comp = defineComponent({ props: { a: String }, emits: ['test'] }) ++ * ++ * const instance = ref>() ++ * instance.$props.a // string | undefined ++ * ``` ++ */ +export type ComponentInstance = T extends { + new (): ComponentPublicInstance; -+} ? InstanceType : T extends FunctionalComponent ? ComponentPublicInstance : T extends ComponentPublicInstanceConstructor ? InstanceType : T extends ComponentDefineOptions ? InstanceType : T extends FunctionalComponent ? ComponentPublicInstance : T extends ComponentPublicInstanceConstructor ? InstanceType : T extends DefineComponentOptions ? InstanceType ? PA : P : Props, RawBindings, D, C, M, Mixin, Extends, E, EE, I, II, S, Options>>> : T extends Component ? ComponentPublicInstance : never; + type HMRComponent = ComponentOptions | ClassComponent; export interface HMRRuntime { createRecord: typeof createRecord; -@@ -1568,12 +1671,12 @@ interface LegacyPublicProperties { +@@ -1568,12 +1734,12 @@ interface LegacyPublicProperties { */ export type CompatVue = Pick & { configureCompat: typeof configureCompat; @@ -329,7 +396,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..e26f82d85eb272844bcffd67cd05dd8e component(name: string): Component | undefined; component(name: string, component: Component): CompatVue; directive(name: string): Directive | undefined; -@@ -1582,7 +1685,7 @@ export type CompatVue = Pick & { +@@ -1582,7 +1748,7 @@ export type CompatVue = Pick & { /** * @deprecated Vue 3 no longer supports extending constructors. */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b206be5f..b0c975b74 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: patchedDependencies: '@vue/runtime-core@3.3.8': - hash: 4orkj7obj2wcx2tgwse3zhn7s4 + hash: lndrozu7pdyaznejpylodc6xjy path: patches/@vue__runtime-core@3.3.8.patch dependencies: @@ -1648,7 +1648,7 @@ packages: '@vue/shared': 3.3.8 dev: true - /@vue/runtime-core@3.3.8(patch_hash=4orkj7obj2wcx2tgwse3zhn7s4): + /@vue/runtime-core@3.3.8(patch_hash=lndrozu7pdyaznejpylodc6xjy): resolution: {integrity: sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==} dependencies: '@vue/reactivity': 3.3.8 @@ -1659,7 +1659,7 @@ packages: /@vue/runtime-dom@3.3.8: resolution: {integrity: sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==} dependencies: - '@vue/runtime-core': 3.3.8(patch_hash=4orkj7obj2wcx2tgwse3zhn7s4) + '@vue/runtime-core': 3.3.8(patch_hash=lndrozu7pdyaznejpylodc6xjy) '@vue/shared': 3.3.8 csstype: 3.1.2 dev: true diff --git a/src/baseWrapper.ts b/src/baseWrapper.ts index 59edd07c2..973aed2b1 100644 --- a/src/baseWrapper.ts +++ b/src/baseWrapper.ts @@ -1,7 +1,8 @@ import { textContent } from './utils' import type { TriggerOptions } from './createDomEvent' import { - ComponentDefineOptions, + DefineComponentOptions, + DefineComponentFromOptions, ComponentInjectOptions, ComponentInstance, ComponentInternalInstance, @@ -131,7 +132,7 @@ export default abstract class BaseWrapper S extends SlotsType = {}, Options = {} >( - selector: ComponentDefineOptions< + selector: DefineComponentOptions< Props, RawBindings, D, @@ -149,7 +150,7 @@ export default abstract class BaseWrapper ): VueWrapper< Props extends DefinedComponent ? ComponentInstance - : CreateComponentPublicInstance< + : DefineComponentFromOptions< Props, RawBindings, D, @@ -158,10 +159,9 @@ export default abstract class BaseWrapper Mixin, Extends, E, - Props, - {}, - true, + EE, I, + II, S, Options > diff --git a/src/mount.ts b/src/mount.ts index a35fb5d69..42e254a3d 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -3,13 +3,9 @@ import { DefineComponent, VNode, ComponentInstance, - ComputedOptions, - MethodOptions, - ComponentOptionsMixin, EmitsOptions, - ComponentInjectOptions, - SlotsType, - ComponentDefineOptions + ComponentObjectPropsOptions, + ExtractPropTypes } from 'vue' import type { ComponentSlots } from 'vue-component-type-helpers' import { createInstance } from './createInstance' @@ -108,24 +104,117 @@ export type ComponentMountingOptions = Omit< // > // ): { props: Props } // defineComponent + +// TODO import from vue +export type ResolveProps = Readonly< + ([Props] extends [string] + ? { [key in Props]?: any } + : [Props] extends [ComponentObjectPropsOptions] + ? ExtractPropTypes + : Props extends never[] + ? {} + : Props) & + ({} extends E ? {} : {}) +> + +// export function mount( +// component: Component & +// DefineComponent< +// any, +// any, +// any, +// any, +// any, +// any, +// any, +// any, +// any, +// any, +// any, +// any, +// any +// >, +// options?: ComponentMountingOptions< +// Component, +// ComponentPropsWithDefaultOptional +// > +// ): VueWrapper> & { +// LOL: Component +// LOOL: ComponentPropsWithDefaultOptional +// } + export function mount< - T extends DefineComponent< - PropsOrOptions, - any, - any, - any, - any, - any, - any, - any, - any, - any - >, - PropsOrOptions extends object + T extends DefineComponent >( originalComponent: T, options?: ComponentMountingOptions> ): VueWrapper> + +// export function mount< +// Props = {}, +// RawBindings = {}, +// D = {}, +// C extends ComputedOptions = {}, +// M extends MethodOptions = {}, +// Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, +// Extends extends ComponentOptionsMixin = ComponentOptionsMixin, +// E extends EmitsOptions = {}, +// EE extends string = string, +// I extends ComponentInjectOptions = {}, +// II extends string = string, +// S extends SlotsType = {}, +// Options = {}, +// Component extends DefineComponentOptions< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S, +// Options +// > = DefineComponentOptions< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S, +// Options +// > +// >( +// componentOptions: DefineComponentOptions< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S, +// Options +// >, +// options?: ComponentMountingOptions< +// Component, +// ComponentPropsWithDefaultOptional +// > +// ): VueWrapper> + // implementation export function mount( inputComponent: any, diff --git a/test-dts/mount.d-test.ts b/test-dts/mount.d-test.ts index 3c6baa561..cfa1c5170 100644 --- a/test-dts/mount.d-test.ts +++ b/test-dts/mount.d-test.ts @@ -85,15 +85,15 @@ mount(AppWithProps, { expectError( mount(AppWithProps, { - // @ts-expect-error wrong prop type should not compile + // @ts-expect-error wrong prop type should not compile props: { a: 2 } }) ) const AppWithArrayProps = { - props: ['a'], + props: ['a'] as ['a'], template: '' -} as const +} // accept props - vm is properly typed expectType( diff --git a/test-dts/shallowMount.d-test.ts b/test-dts/shallowMount.d-test.ts index af9c5fa5c..eb769cced 100644 --- a/test-dts/shallowMount.d-test.ts +++ b/test-dts/shallowMount.d-test.ts @@ -65,9 +65,9 @@ expectError( ) const AppWithArrayProps = { - props: ['a'], + props: ['a'] as ['a'], template: '' -} as const +} // accept props // vm is properly typed diff --git a/test-dts/wrapper.d-test.ts b/test-dts/wrapper.d-test.ts index cf3b86236..8c96c1c0d 100644 --- a/test-dts/wrapper.d-test.ts +++ b/test-dts/wrapper.d-test.ts @@ -146,20 +146,48 @@ expectType(propsWrapper.props('bar')) // @ts-expect-error :: unknown prop propsWrapper.props('badProp') -const requiredPropsWrapper = mount( - defineComponent({ - props: { - foo: { type: String, required: true }, - bar: { type: Number, required: true } - } - }), - { - props: { - foo: 'abc', - bar: 123 - } +// const cc = defineComponent({ +// props: { +// foo: { type: String, required: true }, +// bar: { type: Number, required: true } +// } +// }) +// mount( +// defineComponent({ +// props: { +// foo: { type: String, required: true }, +// bar: { type: Number, required: true } +// } +// }), +// { +// props: { +// foo: 'aaa', +// bar: 123 +// } +// } +// ) + +// mount({ +// props: { +// a: String +// }, +// setup(props) { +// props +// } +// }) + +const c = defineComponent({ + props: { + foo: { type: String, required: true }, + bar: { type: Number, required: true } } -) +}) +const requiredPropsWrapper = mount(c, { + props: { + foo: 'abc', + bar: 123 + } +}) requiredPropsWrapper.setProps({ foo: 'abc' From 3dd6bfacee72c25719040503a2d26d845539de1e Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 20 Nov 2023 14:13:21 +0000 Subject: [PATCH 11/15] update --- patches/@vue__runtime-core@3.3.8.patch | 38 ++++-- pnpm-lock.yaml | 6 +- src/mount.ts | 181 +------------------------ test-dts/wrapper.d-test.ts | 81 ++++++----- 4 files changed, 79 insertions(+), 227 deletions(-) diff --git a/patches/@vue__runtime-core@3.3.8.patch b/patches/@vue__runtime-core@3.3.8.patch index 7dfc02e59..f460c9c78 100644 --- a/patches/@vue__runtime-core@3.3.8.patch +++ b/patches/@vue__runtime-core@3.3.8.patch @@ -1,5 +1,5 @@ diff --git a/dist/runtime-core.d.ts b/dist/runtime-core.d.ts -index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..a4377187d514a0663c3a35c073e794b4cfd98d76 100644 +index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..539385c2754e1b5882ac6c3bc272372f2b43018c 100644 --- a/dist/runtime-core.d.ts +++ b/dist/runtime-core.d.ts @@ -1,7 +1,7 @@ @@ -252,7 +252,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..a4377187d514a0663c3a35c073e794b4 export declare const ssrContextKey: unique symbol; export declare const useSSRContext: >() => T | undefined; -@@ -1437,6 +1481,128 @@ interface DevtoolsHook { +@@ -1437,6 +1481,138 @@ interface DevtoolsHook { export declare let devtools: DevtoolsHook; export declare function setDevtoolsHook(hook: DevtoolsHook, target: any): void; @@ -280,9 +280,9 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..a4377187d514a0663c3a35c073e794b4 + slots: infer S; +} ? S : T extends { + slots: infer S extends Slots; -+} ? S : T extends (props: any, opts: { -+ slots: infer S; -+}) => any ? S : T extends { ++} ? S : T extends (props: any, opts: infer Ctx extends { ++ slots: any; ++}) => any ? Ctx['slots'] : T extends (props: any, opts: SetupContext) => any ? S : T extends { + new (): { + $slots: infer S extends Slots; + }; @@ -315,7 +315,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..a4377187d514a0663c3a35c073e794b4 + */ +export type ResolvePropsFromOptions = T extends { + props: infer P; -+} ? [P] extends [Array] ? [PA] extends [string] ? ObjectToComponentProps> : never : P : T extends (props: infer P) => any ? ObjectToComponentProps

: T extends { ++} ? [P] extends [Array] ? [PA] extends [string] ? ObjectToComponentProps> : never : P : T extends (props: infer P, ctx?: any) => any ? ObjectToComponentProps

: T extends { + new (): { + $props: infer P; + }; @@ -327,7 +327,9 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..a4377187d514a0663c3a35c073e794b4 +export type ComponentPropsWithDefaultOptional = (ResolvePropsFromOptions extends infer Props ? ExtractDefaultPropTypes extends infer Defaults ? Partial & Omit, keyof Defaults> : {} : {}) & (T extends { + props: any; +} ? ResolveMixinProps> : T extends ((...args: any) => any) | (abstract new (...args: any) => any) ? {} : ResolveMixinProps); ++type FixMixinResolve = [T] extends [never] ? {} : T; +type ResolveMixinProps = UnwrapMixinsType, 'P'>; ++type ResolveMixinData = FixMixinResolve, 'D'>>; +/** + * Returns the emits as props + */ @@ -351,16 +353,24 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..a4377187d514a0663c3a35c073e794b4 + $props: infer P; +} ? P : (ExtractComponentProp extends infer P ? P extends Readonly> ? [V] extends [string] ? Readonly<{ + [key in V]?: any; -+}> : {} : P extends ComponentPropsOptions ? ExtractPropTypes

: P : {}) & (T extends { -+ props: any; -+} ? ResolveMixinProps> : ResolveMixinProps); ++}> : {} : P extends ComponentPropsOptions ? ExtractPropTypes

: P : {}) & ResolveMixinProps; ++export type RetrieveSlotArgument = (...args: T) => any; +/** + * Returns runtime type for `slots` + */ -+export type ComponentSlots = ExtractComponentSlots extends infer S ? { -+ [K in keyof S]: S[K] extends Slot ? (arg: V) => VNode : never; -+} : {}; ++export type ComponentSlots = ExtractComponentSlots extends infer S ? S extends SlotsType ? Record extends SS ? { ++ [K in keyof S & string]: S[K] extends RetrieveSlotArgument ? (...arg: A) => VNode[] : (arg: S[K]) => VNode[]; ++} : UnwrapSlotsType : S extends Record ? { ++ [K in keyof S & string]: S[K] extends RetrieveSlotArgument ? (...arg: A) => VNode[] : (arg: S[K]) => VNode[]; ++} : {} : {}; +export type ComponentEmits = ExtractComponentEmits extends infer E ? {} extends E ? () => void : EmitFn : () => void; ++export type ComponentData = (T extends { ++ data: () => infer D; ++} ? D : T extends { ++ setup(...args: any[]): infer S; ++} ? S extends Record ? S : {} : T extends new () => { ++ data: () => infer D; ++} ? D : {}) & ResolveMixinData; +/** + * Retrieves the component public instance + * @@ -381,7 +391,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..a4377187d514a0663c3a35c073e794b4 type HMRComponent = ComponentOptions | ClassComponent; export interface HMRRuntime { createRecord: typeof createRecord; -@@ -1568,12 +1734,12 @@ interface LegacyPublicProperties { +@@ -1568,12 +1744,12 @@ interface LegacyPublicProperties { */ export type CompatVue = Pick & { configureCompat: typeof configureCompat; @@ -396,7 +406,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..a4377187d514a0663c3a35c073e794b4 component(name: string): Component | undefined; component(name: string, component: Component): CompatVue; directive(name: string): Directive | undefined; -@@ -1582,7 +1748,7 @@ export type CompatVue = Pick & { +@@ -1582,7 +1758,7 @@ export type CompatVue = Pick & { /** * @deprecated Vue 3 no longer supports extending constructors. */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b0c975b74..6cdec73a1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: patchedDependencies: '@vue/runtime-core@3.3.8': - hash: lndrozu7pdyaznejpylodc6xjy + hash: gs63hy3r6gfy6zua5pjzzluvvq path: patches/@vue__runtime-core@3.3.8.patch dependencies: @@ -1648,7 +1648,7 @@ packages: '@vue/shared': 3.3.8 dev: true - /@vue/runtime-core@3.3.8(patch_hash=lndrozu7pdyaznejpylodc6xjy): + /@vue/runtime-core@3.3.8(patch_hash=gs63hy3r6gfy6zua5pjzzluvvq): resolution: {integrity: sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==} dependencies: '@vue/reactivity': 3.3.8 @@ -1659,7 +1659,7 @@ packages: /@vue/runtime-dom@3.3.8: resolution: {integrity: sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==} dependencies: - '@vue/runtime-core': 3.3.8(patch_hash=lndrozu7pdyaznejpylodc6xjy) + '@vue/runtime-core': 3.3.8(patch_hash=gs63hy3r6gfy6zua5pjzzluvvq) '@vue/shared': 3.3.8 csstype: 3.1.2 dev: true diff --git a/src/mount.ts b/src/mount.ts index 42e254a3d..bd8f8a893 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -3,11 +3,8 @@ import { DefineComponent, VNode, ComponentInstance, - EmitsOptions, - ComponentObjectPropsOptions, - ExtractPropTypes + ComponentSlots } from 'vue' -import type { ComponentSlots } from 'vue-component-type-helpers' import { createInstance } from './createInstance' import { MountingOptions } from './types' import { trackInstance } from './utils/autoUnmount' @@ -15,10 +12,6 @@ import { VueWrapper } from './vueWrapper' import { createVueWrapper } from './wrapperFactory' import { ComponentPropsWithDefaultOptional } from 'vue' -type ShimSlotReturnType = T extends (...args: infer P) => any - ? (...args: P) => any - : never - type WithArray = T | T[] type ComponentData = T extends { data?(...args: any): infer D } ? D : {} @@ -29,7 +22,7 @@ export type ComponentMountingOptions = Omit< > & { slots?: { [K in keyof ComponentSlots]: WithArray< - | ShimSlotReturnType[K]> + | ComponentSlots[K] | string | VNode | (new () => any) @@ -38,111 +31,6 @@ export type ComponentMountingOptions = Omit< } } & Record -// export function mount< -// Props = never, -// RawBindings = {}, -// D = {}, -// C extends ComputedOptions = {}, -// M extends MethodOptions = {}, -// Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, -// Extends extends ComponentOptionsMixin = ComponentOptionsMixin, -// E extends EmitsOptions = {}, -// EE extends string = string, -// I extends ComponentInjectOptions = {}, -// II extends string = string, -// S extends SlotsType = {}, -// Options = {} -// >( -// originalComponent: ComponentDefineOptions< -// Props, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// I, -// II, -// S, -// Options -// >, -// options?: ComponentMountingOptions< -// ComponentDefineOptions< -// Props, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// I, -// II, -// S, -// Options -// >, -// ComponentPropsWithDefaultOptional< -// ComponentDefineOptions< -// Props, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// I, -// II, -// S, -// Options -// > -// > -// > -// ): { props: Props } -// defineComponent - -// TODO import from vue -export type ResolveProps = Readonly< - ([Props] extends [string] - ? { [key in Props]?: any } - : [Props] extends [ComponentObjectPropsOptions] - ? ExtractPropTypes - : Props extends never[] - ? {} - : Props) & - ({} extends E ? {} : {}) -> - -// export function mount( -// component: Component & -// DefineComponent< -// any, -// any, -// any, -// any, -// any, -// any, -// any, -// any, -// any, -// any, -// any, -// any, -// any -// >, -// options?: ComponentMountingOptions< -// Component, -// ComponentPropsWithDefaultOptional -// > -// ): VueWrapper> & { -// LOL: Component -// LOOL: ComponentPropsWithDefaultOptional -// } - export function mount< T extends DefineComponent >( @@ -150,71 +38,6 @@ export function mount< options?: ComponentMountingOptions> ): VueWrapper> -// export function mount< -// Props = {}, -// RawBindings = {}, -// D = {}, -// C extends ComputedOptions = {}, -// M extends MethodOptions = {}, -// Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, -// Extends extends ComponentOptionsMixin = ComponentOptionsMixin, -// E extends EmitsOptions = {}, -// EE extends string = string, -// I extends ComponentInjectOptions = {}, -// II extends string = string, -// S extends SlotsType = {}, -// Options = {}, -// Component extends DefineComponentOptions< -// Props, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// I, -// II, -// S, -// Options -// > = DefineComponentOptions< -// Props, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// I, -// II, -// S, -// Options -// > -// >( -// componentOptions: DefineComponentOptions< -// Props, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// I, -// II, -// S, -// Options -// >, -// options?: ComponentMountingOptions< -// Component, -// ComponentPropsWithDefaultOptional -// > -// ): VueWrapper> - // implementation export function mount( inputComponent: any, diff --git a/test-dts/wrapper.d-test.ts b/test-dts/wrapper.d-test.ts index 8c96c1c0d..4d441d615 100644 --- a/test-dts/wrapper.d-test.ts +++ b/test-dts/wrapper.d-test.ts @@ -1,5 +1,5 @@ import { expectType } from './index' -import { defineComponent } from 'vue' +import { SlotsType, defineComponent } from 'vue' import { mount } from '../src' const AppWithDefine = defineComponent({ @@ -146,36 +146,6 @@ expectType(propsWrapper.props('bar')) // @ts-expect-error :: unknown prop propsWrapper.props('badProp') -// const cc = defineComponent({ -// props: { -// foo: { type: String, required: true }, -// bar: { type: Number, required: true } -// } -// }) -// mount( -// defineComponent({ -// props: { -// foo: { type: String, required: true }, -// bar: { type: Number, required: true } -// } -// }), -// { -// props: { -// foo: 'aaa', -// bar: 123 -// } -// } -// ) - -// mount({ -// props: { -// a: String -// }, -// setup(props) { -// props -// } -// }) - const c = defineComponent({ props: { foo: { type: String, required: true }, @@ -197,3 +167,52 @@ requiredPropsWrapper.setProps({ // @ts-expect-error wrong type foo: 1 }) + +// slots +mount( + defineComponent({ + slots: {} as SlotsType<{ + default: (test: { foo: string }) => void + }> + }), + { + slots: { + default: 'test' + } + } +) + +// slot type + +mount( + defineComponent({ + slots: {} as SlotsType<{ + default: (test: { foo: string }) => void + }> + }), + { + slots: { + // @ts-expect-error wrong type + nonExistent: 'test', + + default: (test) => { + expectType<{ foo: string }>(test) + // @ts-expect-error not any + expectType<{ bar: any }>(test) + } + } + } +) + +// required slots +mount( + defineComponent({ + slots: {} as SlotsType<{ + default: (test: { foo: string }) => void + }> + }), + { + // @ts-expect-error missing required slot + slots: {} + } +) From 41f6f94787105868bc15b3bcc22bdeb1687fbd9b Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 20 Nov 2023 14:16:32 +0000 Subject: [PATCH 12/15] lint --- src/vueWrapper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 3aea3a33d..0efebafd9 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -88,8 +88,8 @@ type ResolveEmitRecord = ExtractComponentEmits extends infer E ? Args extends { length: 0 } ? void : Args extends { length: 1 } - ? Args[0] - : Args + ? Args[0] + : Args : void)[] } : never From a33efb15bc6cdbd55ba59daf14ba0dcc6ec52412 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 20 Nov 2023 14:19:10 +0000 Subject: [PATCH 13/15] set deep partial --- src/vueWrapper.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 0efebafd9..8e839f266 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -94,6 +94,10 @@ type ResolveEmitRecord = ExtractComponentEmits extends infer E } : never +type DeepPartial = { + [P in keyof T]?: DeepPartial +} + export class VueWrapper< VM = unknown, T extends ComponentPublicInstance = ComponentPublicInstance & VM @@ -265,7 +269,7 @@ export class VueWrapper< return domWrapper.isVisible() } - setData(data: Partial): Promise { + setData(data: DeepPartial): Promise { mergeDeep(this.componentVM.$data, data) return nextTick() } From 36d79e235ea2875212e62d424fa8776c6b4784e3 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 20 Nov 2023 14:36:18 +0000 Subject: [PATCH 14/15] fix some vue-tsc --- src/baseWrapper.ts | 17 +++++++++-------- src/types.ts | 5 +++++ tests/setProps.spec.ts | 1 - 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/baseWrapper.ts b/src/baseWrapper.ts index 973aed2b1..a1eb9ace0 100644 --- a/src/baseWrapper.ts +++ b/src/baseWrapper.ts @@ -26,6 +26,7 @@ import { FindComponentSelector, NameSelector, RefSelector, + UnknownRenderedVue, VueNode } from './types' import WrapperLike from './interfaces/wrapperLike' @@ -185,15 +186,15 @@ export default abstract class BaseWrapper selector: string ): DOMWrapper + // searching by name or ref always results in VueWrapper + findComponent( + selector: NameSelector | RefSelector + ): VueWrapper // searching for component created via defineComponent results in VueWrapper of proper type findComponent( selector: T | Exclude ): VueWrapper> - // searching by name or ref always results in VueWrapper - findComponent( - selector: NameSelector | RefSelector - ): VueWrapper findComponent( selector: T | FindComponentSelector ): VueWrapper @@ -340,6 +341,10 @@ export default abstract class BaseWrapper } getComponent(selector: string): Omit + // searching by name or ref always results in VueWrapper + getComponent( + selector: NameSelector | RefSelector + ): Omit, 'exists'> getComponent( selector: T | Exclude ): Omit>, 'exists'> @@ -347,10 +352,6 @@ export default abstract class BaseWrapper getComponent( selector: T | string ): Omit, 'exists'> - // searching by name or ref always results in VueWrapper - getComponent( - selector: NameSelector | RefSelector - ): Omit getComponent( selector: T | FindComponentSelector ): Omit, 'exists'> diff --git a/src/types.ts b/src/types.ts index f649a7a1e..a0e7f03d4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -167,3 +167,8 @@ export type VueNode = T & { export type VueElement = VueNode export type DefinedComponent = Component + +export type UnknownRenderedVue = { + $props: Record + $data: Record +} diff --git a/tests/setProps.spec.ts b/tests/setProps.spec.ts index f736d0001..bc287950a 100644 --- a/tests/setProps.spec.ts +++ b/tests/setProps.spec.ts @@ -142,7 +142,6 @@ describe('setProps', () => { }) const FooResult = wrapper.findComponent({ name: 'Foo' }) - // @ts-expect-error not valid prop expect(() => FooResult.setProps({ baz: 'bin' })).toThrowError( 'You can only use setProps on your mounted component' ) From 8aaa9d5eac721cfea5a73ea4be1e779d896dfe02 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 20 Nov 2023 15:06:04 +0000 Subject: [PATCH 15/15] more improvements --- patches/@vue__runtime-core@3.3.8.patch | 4 ++-- pnpm-lock.yaml | 6 +++--- src/vnodeTransformers/stubComponentsTransformer.ts | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/patches/@vue__runtime-core@3.3.8.patch b/patches/@vue__runtime-core@3.3.8.patch index f460c9c78..a9628558d 100644 --- a/patches/@vue__runtime-core@3.3.8.patch +++ b/patches/@vue__runtime-core@3.3.8.patch @@ -1,5 +1,5 @@ diff --git a/dist/runtime-core.d.ts b/dist/runtime-core.d.ts -index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..539385c2754e1b5882ac6c3bc272372f2b43018c 100644 +index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..d8c6502f88b63d58dd9844f460c39d519754f396 100644 --- a/dist/runtime-core.d.ts +++ b/dist/runtime-core.d.ts @@ -1,7 +1,7 @@ @@ -354,7 +354,7 @@ index 5d4c1fb2c6859f7982ea7bb55f65a5c613d91038..539385c2754e1b5882ac6c3bc272372f +} ? P : (ExtractComponentProp extends infer P ? P extends Readonly> ? [V] extends [string] ? Readonly<{ + [key in V]?: any; +}> : {} : P extends ComponentPropsOptions ? ExtractPropTypes

: P : {}) & ResolveMixinProps; -+export type RetrieveSlotArgument = (...args: T) => any; ++export type RetrieveSlotArgument = ((...args: T) => any) | undefined; +/** + * Returns runtime type for `slots` + */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6cdec73a1..06047af33 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: patchedDependencies: '@vue/runtime-core@3.3.8': - hash: gs63hy3r6gfy6zua5pjzzluvvq + hash: vlyf6crnsg7mzuzbrcghr6xpce path: patches/@vue__runtime-core@3.3.8.patch dependencies: @@ -1648,7 +1648,7 @@ packages: '@vue/shared': 3.3.8 dev: true - /@vue/runtime-core@3.3.8(patch_hash=gs63hy3r6gfy6zua5pjzzluvvq): + /@vue/runtime-core@3.3.8(patch_hash=vlyf6crnsg7mzuzbrcghr6xpce): resolution: {integrity: sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==} dependencies: '@vue/reactivity': 3.3.8 @@ -1659,7 +1659,7 @@ packages: /@vue/runtime-dom@3.3.8: resolution: {integrity: sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==} dependencies: - '@vue/runtime-core': 3.3.8(patch_hash=gs63hy3r6gfy6zua5pjzzluvvq) + '@vue/runtime-core': 3.3.8(patch_hash=vlyf6crnsg7mzuzbrcghr6xpce) '@vue/shared': 3.3.8 csstype: 3.1.2 dev: true diff --git a/src/vnodeTransformers/stubComponentsTransformer.ts b/src/vnodeTransformers/stubComponentsTransformer.ts index 3651d2bc3..f11f74663 100644 --- a/src/vnodeTransformers/stubComponentsTransformer.ts +++ b/src/vnodeTransformers/stubComponentsTransformer.ts @@ -17,7 +17,8 @@ import { ComponentPropsOptions, ComponentObjectPropsOptions, Component, - AsyncComponentOptions + AsyncComponentOptions, + VNode } from 'vue' import { hyphenate } from '../utils/vueShared' import { matchName } from '../utils/matchName' @@ -34,7 +35,7 @@ export type CustomCreateStub = (params: { name: string component: Component registerStub: (config: { source: Component; stub: Component }) => void -}) => ConcreteComponent +}) => ConcreteComponent | VNode interface StubOptions { name: string