From b256412160aee04539f7fc68cd600a2948d8f4d1 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 6 Nov 2023 10:35:20 +0000 Subject: [PATCH 01/79] WIP: component helper types --- .../dts-test/componentTypeHelpers.test-d.ts | 30 +++++ .../runtime-core/src/apiAsyncComponent.ts | 2 +- .../runtime-core/src/apiDefineComponent.ts | 122 ++++++++++++------ .../runtime-core/src/compat/compatConfig.ts | 13 ++ .../src/compat/componentVModel.ts | 9 +- packages/runtime-core/src/compat/global.ts | 24 ++-- packages/runtime-core/src/compat/instance.ts | 11 +- packages/runtime-core/src/component.ts | 8 +- packages/runtime-core/src/componentOptions.ts | 83 ++++++------ packages/runtime-core/src/componentProps.ts | 10 +- .../runtime-core/src/componentTypeHelpers.ts | 48 +++++++ .../runtime-core/src/components/KeepAlive.ts | 5 +- packages/runtime-core/src/customFormatter.ts | 6 +- packages/runtime-core/src/hmr.ts | 2 +- packages/runtime-core/src/index.ts | 2 + packages/runtime-dom/src/apiCustomElement.ts | 7 +- 16 files changed, 271 insertions(+), 111 deletions(-) create mode 100644 packages/dts-test/componentTypeHelpers.test-d.ts create mode 100644 packages/runtime-core/src/componentTypeHelpers.ts diff --git a/packages/dts-test/componentTypeHelpers.test-d.ts b/packages/dts-test/componentTypeHelpers.test-d.ts new file mode 100644 index 00000000000..d3a97a53fb6 --- /dev/null +++ b/packages/dts-test/componentTypeHelpers.test-d.ts @@ -0,0 +1,30 @@ +// import { expectType, describe } from './utils' + +// import { +// ExtractComponentOptions, +// ExtractComponentSlots, +// ExtractComponentEmits, +// defineComponent +// } from 'vue' + +// describe('Extract Component Options', () => { +// describe('define Component', () => { +// // const comp = { +// // props: ['bar'] +// // } as const + +// const Comp = defineComponent({ +// props: ['bar'] +// }) + +// const a = {} as unknown as ExtractComponentOptions + +// a.props + +// // expectType>(comp) +// }) + +// describe('async component', () => {}) + +// describe('options object', () => {}) +// }) diff --git a/packages/runtime-core/src/apiAsyncComponent.ts b/packages/runtime-core/src/apiAsyncComponent.ts index 342339042ef..3ad4930f4ef 100644 --- a/packages/runtime-core/src/apiAsyncComponent.ts +++ b/packages/runtime-core/src/apiAsyncComponent.ts @@ -207,7 +207,7 @@ export function defineAsyncComponent< } } } - }) as T + }) as unknown as T } function createInnerComp( diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 272bb548751..6b42b209cde 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -6,9 +6,9 @@ import { ComponentOptionsWithObjectProps, ComponentOptionsMixin, RenderFunction, - ComponentOptionsBase, ComponentInjectOptions, - ComponentOptions + ComponentOptions, + ComponentOptionsBase } from './componentOptions' import { SetupContext, @@ -54,7 +54,10 @@ export type DefineComponent< PP = PublicProps, Props = ResolveProps, Defaults = ExtractDefaultPropTypes, - S extends SlotsType = {} + I extends ComponentInjectOptions = {}, + II extends string = string, + S extends SlotsType = {}, + Options = {} > = ComponentPublicInstanceConstructor< CreateComponentPublicInstance< Props, @@ -68,7 +71,7 @@ export type DefineComponent< PP & Props, Defaults, true, - {}, + I, S > & Props @@ -84,10 +87,30 @@ export type DefineComponent< E, EE, Defaults, - {}, - string, - S - > & + I, + II, + S, + PropsOrPropOptions + > & { props: Props } & Options & + // Omit< + // Options, + // keyof ComponentOptionsBase< + // Props, + // RawBindings, + // D, + // C, + // M, + // Mixin, + // Extends, + // E, + // EE, + // Defaults, + // I, + // II, + // S + // > + // > & + PP // defineComponent is a utility that is primarily used for type inference @@ -143,24 +166,26 @@ export function defineComponent< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = {}, EE extends string = string, - S extends SlotsType = {}, I extends ComponentInjectOptions = {}, - II extends string = string + II extends string = string, + S extends SlotsType = {}, + Options = {} >( - options: ComponentOptionsWithoutProps< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - I, - II, - S - > + options: Options & + ComponentOptionsWithoutProps< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S + > ): DefineComponent< Props, RawBindings, @@ -174,12 +199,16 @@ export function defineComponent< PublicProps, ResolveProps, ExtractDefaultPropTypes, - S + I, + II, + S, + Options > // overload 3: object format with array props declaration // props inferred as { [key in PropNames]?: any } // return type is for Vetur and TSX support + export function defineComponent< PropNames extends string, RawBindings, @@ -193,22 +222,24 @@ export function defineComponent< S extends SlotsType = {}, I extends ComponentInjectOptions = {}, II extends string = string, - Props = Readonly<{ [key in PropNames]?: any }> + Props = Readonly<{ [key in PropNames]?: any }>, + Options = {} >( - options: ComponentOptionsWithArrayProps< - PropNames, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - I, - II, - S - > + options: Options & + ComponentOptionsWithArrayProps< + PropNames, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S + > ): DefineComponent< Props, RawBindings, @@ -222,7 +253,10 @@ export function defineComponent< PublicProps, ResolveProps, ExtractDefaultPropTypes, - S + I, + II, + S, + Options > // overload 4: object format with object props declaration @@ -239,9 +273,9 @@ export function defineComponent< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = {}, EE extends string = string, - S extends SlotsType = {}, I extends ComponentInjectOptions = {}, - II extends string = string + II extends string = string, + S extends SlotsType = {} >( options: ComponentOptionsWithObjectProps< PropsOptions, @@ -270,6 +304,8 @@ export function defineComponent< PublicProps, ResolveProps, ExtractDefaultPropTypes, + I, + II, S > diff --git a/packages/runtime-core/src/compat/compatConfig.ts b/packages/runtime-core/src/compat/compatConfig.ts index 88b58fdfab0..e6afa2754d4 100644 --- a/packages/runtime-core/src/compat/compatConfig.ts +++ b/packages/runtime-core/src/compat/compatConfig.ts @@ -10,6 +10,19 @@ import { } from '../component' import { warn } from '../warning' +export interface ComponentOptionsCompat extends ComponentOptions { + model?: any + el?: any + + _base?: any + options?: any + + propsData?: any + parent?: any + + __isBuildIn?: boolean +} + export const enum DeprecationTypes { GLOBAL_MOUNT = 'GLOBAL_MOUNT', GLOBAL_MOUNT_CONTAINER = 'GLOBAL_MOUNT_CONTAINER', diff --git a/packages/runtime-core/src/compat/componentVModel.ts b/packages/runtime-core/src/compat/componentVModel.ts index b446fb4274d..32b84fb5a8e 100644 --- a/packages/runtime-core/src/compat/componentVModel.ts +++ b/packages/runtime-core/src/compat/componentVModel.ts @@ -1,12 +1,13 @@ import { extend, ShapeFlags } from '@vue/shared' -import { ComponentInternalInstance, ComponentOptions } from '../component' +import { ComponentInternalInstance } from '../component' import { callWithErrorHandling, ErrorCodes } from '../errorHandling' import { VNode } from '../vnode' import { popWarningContext, pushWarningContext } from '../warning' import { DeprecationTypes, warnDeprecation, - isCompatEnabled + isCompatEnabled, + ComponentOptionsCompat } from './compatConfig' export const compatModelEventPrefix = `onModelCompat:` @@ -15,7 +16,7 @@ const warnedTypes = new WeakSet() export function convertLegacyVModelProps(vnode: VNode) { const { type, shapeFlag, props, dynamicProps } = vnode - const comp = type as ComponentOptions + const comp = type as ComponentOptionsCompat if (shapeFlag & ShapeFlags.COMPONENT && props && 'modelValue' in props) { if ( !isCompatEnabled( @@ -55,7 +56,7 @@ export function convertLegacyVModelProps(vnode: VNode) { } } -function applyModelFromMixins(model: any, mixins?: ComponentOptions[]) { +function applyModelFromMixins(model: any, mixins?: ComponentOptionsCompat[]) { if (mixins) { mixins.forEach(m => { if (m.model) extend(model, m.model) diff --git a/packages/runtime-core/src/compat/global.ts b/packages/runtime-core/src/compat/global.ts index 9f1a6d1cd12..f52fbc31320 100644 --- a/packages/runtime-core/src/compat/global.ts +++ b/packages/runtime-core/src/compat/global.ts @@ -27,7 +27,6 @@ import { } from '../apiCreateApp' import { Component, - ComponentOptions, createComponentInstance, finishComponentSetup, isRuntimeOnly, @@ -55,7 +54,8 @@ import { assertCompatEnabled, configureCompat, isCompatEnabled, - softAssertCompatEnabled + softAssertCompatEnabled, + ComponentOptionsCompat } from './compatConfig' import { LegacyPublicInstance } from './instance' @@ -70,7 +70,7 @@ export type CompatVue = Pick & { // no inference here since these types are not meant for actual use - they // are merely here to provide type checks for internal implementation and // information for migration. - new (options?: ComponentOptions): LegacyPublicInstance + new (options?: ComponentOptionsCompat): LegacyPublicInstance version: string config: AppConfig & LegacyConfig @@ -78,7 +78,7 @@ export type CompatVue = Pick & { 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 @@ -90,7 +90,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. */ @@ -114,7 +114,7 @@ export type CompatVue = Pick & { /** * @internal */ - options: ComponentOptions + options: ComponentOptionsCompat /** * @internal */ @@ -139,12 +139,12 @@ export function createCompatVue( singletonApp = createSingletonApp({}) const Vue: CompatVue = (singletonCtor = function Vue( - options: ComponentOptions = {} + options: ComponentOptionsCompat = {} ) { return createCompatApp(options, Vue) } as any) - function createCompatApp(options: ComponentOptions = {}, Ctor: any) { + function createCompatApp(options: ComponentOptionsCompat = {}, Ctor: any) { assertCompatEnabled(DeprecationTypes.GLOBAL_MOUNT, null) const { data } = options @@ -214,7 +214,7 @@ export function createCompatVue( const extendCache = new WeakMap() - function extendCtor(this: any, extendOptions: ComponentOptions = {}) { + function extendCtor(this: any, extendOptions: ComponentOptionsCompat = {}) { assertCompatEnabled(DeprecationTypes.GLOBAL_EXTEND, null) if (isFunction(extendOptions)) { extendOptions = extendOptions.options @@ -225,7 +225,7 @@ export function createCompatVue( } const Super = this - function SubVue(inlineOptions?: ComponentOptions) { + function SubVue(inlineOptions?: ComponentOptionsCompat) { if (!inlineOptions) { return createCompatApp(SubVue.options, SubVue) } else { @@ -454,7 +454,7 @@ function installCompatMount( * mounting it, which is no longer possible in Vue 3 - this internal * function simulates that behavior. */ - app._createRoot = options => { + app._createRoot = (options: ComponentOptionsCompat) => { const component = app._component const vnode = createVNode(component, options.propsData || null) vnode.appContext = context @@ -530,7 +530,7 @@ function installCompatMount( } } instance.render = null - ;(component as ComponentOptions).template = container.innerHTML + ;(component as ComponentOptionsCompat).template = container.innerHTML finishComponentSetup(instance, false, true /* skip options */) } diff --git a/packages/runtime-core/src/compat/instance.ts b/packages/runtime-core/src/compat/instance.ts index e6baeda6a8e..df942e951d1 100644 --- a/packages/runtime-core/src/compat/instance.ts +++ b/packages/runtime-core/src/compat/instance.ts @@ -12,6 +12,7 @@ import { } from '../componentPublicInstance' import { getCompatChildren } from './instanceChildren' import { + ComponentOptionsCompat, DeprecationTypes, assertCompatEnabled, isCompatEnabled @@ -37,7 +38,10 @@ import { import { resolveFilter } from '../helpers/resolveAssets' import { InternalSlots, Slots } from '../componentSlots' import { ContextualRenderFn } from '../componentRenderContext' -import { resolveMergedOptions } from '../componentOptions' +import { + MergedComponentOptions, + resolveMergedOptions +} from '../componentOptions' export type LegacyPublicInstance = ComponentPublicInstance & LegacyPublicProperties @@ -132,7 +136,10 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) { // inject additional properties into $options for compat // e.g. vuex needs this.$options.parent $options: i => { - const res = extend({}, resolveMergedOptions(i)) + const res = extend( + {}, + resolveMergedOptions(i) + ) as MergedComponentOptions & ComponentOptionsCompat res.parent = i.proxy!.$parent res.propsData = i.vnode.props return res diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 57a53a39b76..d2676d19cb2 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -158,10 +158,12 @@ export type ConcreteComponent< RawBindings = any, D = any, C extends ComputedOptions = ComputedOptions, - M extends MethodOptions = MethodOptions + M extends MethodOptions = MethodOptions, + E extends EmitsOptions = any, + S extends SlotsType = any > = - | ComponentOptions - | FunctionalComponent + | ComponentOptions + | FunctionalComponent /** * A type used in public APIs where a component type is expected. diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index de4d304448a..f8e0b1b5cc0 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -67,7 +67,7 @@ import { warn } from './warning' import { VNodeChild } from './vnode' import { callWithAsyncErrorHandling } from './errorHandling' import { deepMergeData } from './compat/data' -import { DeprecationTypes } from './compat/compatConfig' +import { ComponentOptionsCompat, DeprecationTypes } from './compat/compatConfig' import { CompatConfig, isCompatEnabled, @@ -111,8 +111,9 @@ export interface ComponentOptionsBase< Defaults = {}, I extends ComponentInjectOptions = {}, II extends string = string, - S extends SlotsType = {} -> extends LegacyOptions, + S extends SlotsType = {}, + OriginalProps = ComponentPropsOptions +> extends LegacyOptions, ComponentInternalOptions, ComponentCustomOptions { setup?: ( @@ -273,20 +274,23 @@ export type ComponentOptionsWithArrayProps< II extends string = string, S extends SlotsType = {}, Props = Prettify>> -> = ComponentOptionsBase< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - {}, - I, - II, - S +> = Omit< + ComponentOptionsBase< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + {}, + I, + II, + S + >, + 'props' > & { props: PropNames[] } & ThisType< @@ -322,20 +326,23 @@ export type ComponentOptionsWithObjectProps< S extends SlotsType = {}, Props = Prettify & EmitsToProps>>, Defaults = ExtractDefaultPropTypes -> = ComponentOptionsBase< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - Defaults, - I, - II, - S +> = Omit< + ComponentOptionsBase< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + Defaults, + I, + II, + S + >, + 'props' > & { props: PropsOptions & ThisType } & ThisType< @@ -355,7 +362,6 @@ export type ComponentOptionsWithObjectProps< S > > - export type ComponentOptions< Props = {}, RawBindings = any, @@ -463,12 +469,14 @@ interface LegacyOptions< Mixin extends ComponentOptionsMixin, Extends extends ComponentOptionsMixin, I extends ComponentInjectOptions, - II extends string + II extends string, + OriginalProps > { compatConfig?: CompatConfig + props?: OriginalProps - // allow any custom options - [key: string]: any + // // allow any custom options + // [key: string]: any // state // Limitation: we cannot expose RawBindings on the `this` context for data @@ -984,7 +992,7 @@ export function resolveMergedOptions( } = instance.appContext const cached = cache.get(base) - let resolved: MergedComponentOptions + let resolved: MergedComponentOptions & ComponentOptionsCompat if (cached) { resolved = cached @@ -993,7 +1001,8 @@ export function resolveMergedOptions( __COMPAT__ && isCompatEnabled(DeprecationTypes.PRIVATE_APIS, instance) ) { - resolved = extend({}, base) as MergedComponentOptions + resolved = extend({}, base) as ComponentOptionsCompat + resolved.parent = instance.parent && instance.parent.proxy resolved.propsData = instance.vnode.props } else { diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 4d402789555..b8f380c3d44 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -37,7 +37,11 @@ import { isEmitListener } from './componentEmits' import { InternalObjectKey } from './vnode' import { AppContext } from './apiCreateApp' import { createPropsDefaultThis } from './compat/props' -import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig' +import { + ComponentOptionsCompat, + isCompatEnabled, + softAssertCompatEnabled +} from './compat/compatConfig' import { DeprecationTypes } from './compat/compatConfig' import { shouldSkipAttr } from './compat/attrsFallthrough' @@ -499,7 +503,7 @@ function resolvePropValue( } export function normalizePropsOptions( - comp: ConcreteComponent, + comp: ConcreteComponent, appContext: AppContext, asMixin = false ): NormalizedPropsOptions { @@ -518,7 +522,7 @@ export function normalizePropsOptions( if (__FEATURE_OPTIONS_API__ && !isFunction(comp)) { const extendProps = (raw: ComponentOptions) => { if (__COMPAT__ && isFunction(raw)) { - raw = raw.options + raw = (raw as ComponentOptionsCompat).options } hasExtends = true const [props, keys] = normalizePropsOptions(raw, appContext, true) diff --git a/packages/runtime-core/src/componentTypeHelpers.ts b/packages/runtime-core/src/componentTypeHelpers.ts new file mode 100644 index 00000000000..fbd4a9dfa52 --- /dev/null +++ b/packages/runtime-core/src/componentTypeHelpers.ts @@ -0,0 +1,48 @@ +// import { DefineComponent } from './apiDefineComponent' +import { ComponentOptionsBase } from './componentOptions' + +export type ExtractComponentOptions = T extends ComponentOptionsBase< + infer Props, + infer RawBindings, + infer D, + infer C, + infer M, + infer Mixin, + infer Extends, + infer E, + infer EE, + infer Defaults, + infer I, + infer II, + infer S +> + ? ComponentOptionsBase< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + Defaults, + I, + II, + S + > + : never + +export type ComponentProps = {} +export type ExtraComponentProp = {} + +export type ComponentSlots = {} +export type ExtractComponentSlots = {} + +export type ComponentEmits = {} +export type ExtractComponentEmits = {} + +export type ComponentInternalInstance = {} +export type ComponentInstance = {} + +// export type ComponentExposed = {} diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index 8c1b6318887..2ac74c89390 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -45,6 +45,7 @@ import { devtoolsComponentAdded } from '../devtools' import { isAsyncWrapper } from '../apiAsyncComponent' import { isSuspense } from './Suspense' import { LifecycleHooks } from '../enums' +import { ComponentOptionsCompat } from '../compat/compatConfig' type MatchPattern = string | RegExp | (string | RegExp)[] @@ -73,7 +74,7 @@ export interface KeepAliveContext extends ComponentRenderContext { export const isKeepAlive = (vnode: VNode): boolean => (vnode.type as any).__isKeepAlive -const KeepAliveImpl: ComponentOptions = { +const KeepAliveImpl: ComponentOptions & { __isKeepAlive: true } = { name: `KeepAlive`, // Marker for special handling inside the renderer. We are not using a === @@ -335,7 +336,7 @@ const KeepAliveImpl: ComponentOptions = { } if (__COMPAT__) { - KeepAliveImpl.__isBuildIn = true + ;(KeepAliveImpl as ComponentOptionsCompat).__isBuildIn = true } // export the public type for h/tsx inference diff --git a/packages/runtime-core/src/customFormatter.ts b/packages/runtime-core/src/customFormatter.ts index 768240feb62..2c267adff20 100644 --- a/packages/runtime-core/src/customFormatter.ts +++ b/packages/runtime-core/src/customFormatter.ts @@ -165,7 +165,11 @@ export function initCustomFormatter() { return extracted } - function isKeyOfType(Comp: ComponentOptions, key: string, type: string) { + function isKeyOfType( + Comp: ComponentOptions & Record, + key: string, + type: string + ) { const opts = Comp[type] if ( (isArray(opts) && opts.includes(key)) || diff --git a/packages/runtime-core/src/hmr.ts b/packages/runtime-core/src/hmr.ts index 1ce66a3da1e..6b438bf9f3f 100644 --- a/packages/runtime-core/src/hmr.ts +++ b/packages/runtime-core/src/hmr.ts @@ -168,7 +168,7 @@ function updateComponentDef( extend(oldComp, newComp) for (const key in oldComp) { if (key !== '__file' && !(key in newComp)) { - delete oldComp[key] + delete oldComp[key as keyof ComponentOptions] } } } diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 98aee757dab..188728a06b0 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -161,6 +161,8 @@ declare module '@vue/reactivity' { } } +export type * from './componentTypeHelpers' + export { TrackOpTypes, TriggerOpTypes } from '@vue/reactivity' export type { Ref, diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index 5662b0b535b..be91eb6a4b1 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -166,7 +166,7 @@ const BaseClass = ( typeof HTMLElement !== 'undefined' ? HTMLElement : class {} ) as typeof HTMLElement -type InnerComponentDef = ConcreteComponent & { styles?: string[] } +type InnerComponentDef = ConcreteComponent & { styles?: string[] } export class VueElement extends BaseClass { /** @@ -255,7 +255,10 @@ export class VueElement extends BaseClass { if (props && !isArray(props)) { for (const key in props) { const opt = props[key] - if (opt === Number || (opt && opt.type === Number)) { + if ( + opt === Number || + (opt && (opt as Record).type === Number) + ) { if (key in this._props) { this._props[key] = toNumber(this._props[key]) } From e1ef6a8abd7629a318d5fc3d2401bf578a9f8262 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 6 Nov 2023 13:54:55 +0000 Subject: [PATCH 02/79] fix one issue --- packages/runtime-core/src/component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index d2676d19cb2..d3990714782 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -178,6 +178,7 @@ export type Component< > = | ConcreteComponent | ComponentPublicInstanceConstructor + | InstanceType> export type { ComponentOptions } From fbd083b18d2824b9aa35be22e133a75140d83221 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 6 Nov 2023 16:16:52 +0000 Subject: [PATCH 03/79] working kinda --- packages/dts-test/defineComponent.test-d.tsx | 11 +- packages/dts-test/h.test-d.ts | 12 +- .../runtime-core/src/apiDefineComponent.ts | 144 +++++++++++++----- packages/runtime-core/src/component.ts | 8 +- packages/runtime-core/src/componentOptions.ts | 37 ++++- packages/runtime-core/src/componentProps.ts | 2 +- packages/runtime-core/src/h.ts | 5 +- 7 files changed, 155 insertions(+), 64 deletions(-) diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index 7466249e10f..4278050dd80 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -1190,7 +1190,7 @@ describe('async setup', () => { // #5948 describe('DefineComponent should infer correct types when assigning to Component', () => { - let component: Component + let component: Component component = defineComponent({ setup(_, { attrs, slots }) { // @ts-expect-error should not be any @@ -1254,6 +1254,10 @@ describe('prop starting with `on*` is broken', () => { }) describe('function syntax w/ generics', () => { + const aa = defineComponent((props: { msg: T }) => { + return () => h('div') + }) + const Comp = defineComponent( // TODO: babel plugin to auto infer runtime props options from type // similar to defineProps<{...}>() @@ -1300,6 +1304,7 @@ describe('function syntax w/ emits', () => { emits: ['foo'] } ) + expectType( {}} />) // @ts-expect-error expectType( {}} />) @@ -1353,12 +1358,12 @@ describe('function syntax w/ runtime props', () => { } ) - // @ts-expect-error string prop names don't match defineComponent( (_props: { msg: string }) => { return () => {} }, { + // @ts-expect-error string prop names don't match props: ['bar'] } ) @@ -1375,7 +1380,6 @@ describe('function syntax w/ runtime props', () => { } ) - // @ts-expect-error prop keys don't match defineComponent( (_props: { msg: string }, ctx) => { return () => {} @@ -1383,6 +1387,7 @@ describe('function syntax w/ runtime props', () => { { props: { msg: String, + // @ts-expect-error prop keys don't match bar: String } } diff --git a/packages/dts-test/h.test-d.ts b/packages/dts-test/h.test-d.ts index f2e984b49b8..47ed62709c9 100644 --- a/packages/dts-test/h.test-d.ts +++ b/packages/dts-test/h.test-d.ts @@ -7,9 +7,10 @@ import { Teleport, Suspense, Component, - resolveComponent + resolveComponent, + ConcreteComponent } from 'vue' -import { describe, expectAssignable } from './utils' +import { describe, expectAssignable, expectType } from './utils' describe('h inference w/ element', () => { // key @@ -84,7 +85,12 @@ describe('h support w/ plain object component', () => { foo: String } } - h(Foo, { foo: 'ok' }) + + expectType(Foo) + + h(Foo, { test: 'asd' }) + const a = h(Foo, { foo: undefined }) + const a1 = h(Foo, { foo: '' }) h(Foo, { foo: 'ok', class: 'extra' }) // no inference in this case }) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 6b42b209cde..ab195109274 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -76,41 +76,24 @@ export type DefineComponent< > & Props > & - ComponentOptionsBase< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - Defaults, - I, - II, - S, - PropsOrPropOptions - > & { props: Props } & Options & - // Omit< - // Options, - // keyof ComponentOptionsBase< - // Props, - // RawBindings, - // D, - // C, - // M, - // Mixin, - // Extends, - // E, - // EE, - // Defaults, - // I, - // II, - // S - // > - // > & - + Omit< + ComponentOptionsBase< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + Defaults, + I, + II, + S + >, + 'props' + > & { props: PropsOrPropOptions } & Omit & PP // defineComponent is a utility that is primarily used for type inference @@ -119,7 +102,25 @@ export type DefineComponent< // for TSX / manual render function / IDE support. // overload 1: direct setup function -// (uses user defined props interface) +export function defineComponent< + Props extends Record, + E extends EmitsOptions = {}, + EE extends string = string, + S extends SlotsType = {}, + Options = {} +>( + setup: ( + props: Props, + ctx: SetupContext + ) => RenderFunction | Promise, + options?: Options & + Pick & { + props?: (keyof Props)[] + emits?: E | EE[] + slots?: S + } +): (props: Props & EmitsToProps) => any + export function defineComponent< Props extends Record, E extends EmitsOptions = {}, @@ -136,11 +137,54 @@ export function defineComponent< slots?: S } ): (props: Props & EmitsToProps) => any + +// (uses user defined props interface) export function defineComponent< Props extends Record, E extends EmitsOptions = {}, EE extends string = string, - S extends SlotsType = {} + S extends SlotsType = {}, + Options = {} +>( + setup: ( + props: Props, + ctx: SetupContext + ) => RenderFunction | Promise, + options?: Options & + Pick & { + props?: (keyof Props)[] + emits?: E | EE[] + slots?: S + } +): DefineComponent< + Props & EmitsToProps, + {}, + {}, + {}, + {}, + {}, + {}, + E, + EE, + PublicProps, + ResolveProps, + ExtractDefaultPropTypes, + {}, + string, + S, + { + name: string + } & Options +> + +// extend({ name: options.name }, extraOptions, { setup: options }))() + +export function defineComponent< + Props extends Record, + E extends EmitsOptions = {}, + EE extends string = string, + S extends SlotsType = {}, + Options = {} >( setup: ( props: Props, @@ -151,7 +195,26 @@ export function defineComponent< emits?: E | EE[] slots?: S } -): (props: Props & EmitsToProps) => any +): DefineComponent< + Props & EmitsToProps, + {}, + {}, + {}, + {}, + {}, + {}, + E, + EE, + PublicProps, + ResolveProps, + ExtractDefaultPropTypes, + {}, + string, + S, + { + name: string + } & Options +> // overload 2: object format with no props // (uses user defined props interface) @@ -311,10 +374,7 @@ export function defineComponent< // implementation, close to no-op /*! #__NO_SIDE_EFFECTS__ */ -export function defineComponent( - options: unknown, - extraOptions?: ComponentOptions -) { +export function defineComponent(options: unknown, extraOptions?: unknown) { return isFunction(options) ? // #8326: extend call and options.name access are considered side-effects // by Rollup, so we have to wrap it in a pure-annotated IIFE. diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index d3990714782..41279124479 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -40,6 +40,7 @@ import { AppContext, createAppContext, AppConfig } from './apiCreateApp' import { Directive, validateDirectiveName } from './directives' import { applyOptions, + ComponentInjectOptions, ComponentOptions, ComputedOptions, MethodOptions, @@ -154,15 +155,16 @@ export interface ClassComponent { * implementation code. */ export type ConcreteComponent< - Props = {}, + Props = Record, 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 + | ComponentOptions | FunctionalComponent /** @@ -178,7 +180,7 @@ export type Component< > = | ConcreteComponent | ComponentPublicInstanceConstructor - | InstanceType> + | ComponentPublicInstance export type { ComponentOptions } diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index f8e0b1b5cc0..e6a0616ded9 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -111,9 +111,8 @@ export interface ComponentOptionsBase< Defaults = {}, I extends ComponentInjectOptions = {}, II extends string = string, - S extends SlotsType = {}, - OriginalProps = ComponentPropsOptions -> extends LegacyOptions, + S extends SlotsType = {} +> extends LegacyOptions, ComponentInternalOptions, ComponentCustomOptions { setup?: ( @@ -362,8 +361,23 @@ export type ComponentOptionsWithObjectProps< S > > + +// Props, +// RawBindings, +// D, +// C extends ComputedOptions, +// M extends MethodOptions, +// Mixin extends ComponentOptionsMixin, +// Extends extends ComponentOptionsMixin, +// E extends EmitsOptions, +// EE extends string = string, +// Defaults = {}, +// I extends ComponentInjectOptions = {}, +// II extends string = string, +// S extends SlotsType = {}, +// OriginalProps extends ComponentPropsOptions = {} export type ComponentOptions< - Props = {}, + Props = Record, RawBindings = any, D = any, C extends ComputedOptions = any, @@ -371,6 +385,7 @@ export type ComponentOptions< Mixin extends ComponentOptionsMixin = any, Extends extends ComponentOptionsMixin = any, E extends EmitsOptions = any, + I extends ComponentInjectOptions = {}, S extends SlotsType = any > = ComponentOptionsBase< Props, @@ -382,6 +397,9 @@ export type ComponentOptions< Extends, E, string, + {}, + I, + string, S > & ThisType< @@ -394,7 +412,11 @@ export type ComponentOptions< Mixin, Extends, E, - Readonly + Readonly, + {}, + false, + I, + S > > @@ -469,11 +491,10 @@ interface LegacyOptions< Mixin extends ComponentOptionsMixin, Extends extends ComponentOptionsMixin, I extends ComponentInjectOptions, - II extends string, - OriginalProps + II extends string > { compatConfig?: CompatConfig - props?: OriginalProps + props?: ComponentPropsOptions // // allow any custom options // [key: string]: any diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index b8f380c3d44..31c99ac0b15 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -513,7 +513,7 @@ export function normalizePropsOptions( return cached } - const raw = comp.props + const raw = comp.props as Record | Array const normalized: NormalizedPropsOptions[0] = {} const needCastKeys: NormalizedPropsOptions[1] = [] diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index 4ca90262f2a..a5a23cb26b6 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -130,9 +130,6 @@ export function h< children?: RawChildren | RawSlots ): VNode -// catch-all for generic component types -export function h(type: Component, children?: RawChildren): VNode - // concrete component export function h

( type: ConcreteComponent | string, @@ -175,7 +172,7 @@ export function h

( ): VNode // catch all types -export function h(type: string | Component, children?: RawChildren): VNode +export function h(type: string | Constructor, children?: RawChildren): VNode export function h

( type: string | Component

, props?: (RawProps & P) | ({} extends P ? null : never), From 893466598a43c11e15bc1e08e82cc6c26f5ae7b2 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 16:20:28 +0000 Subject: [PATCH 04/79] [autofix.ci] apply automated fixes --- packages/runtime-core/src/compat/compatConfig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/src/compat/compatConfig.ts b/packages/runtime-core/src/compat/compatConfig.ts index e6afa2754d4..ca555b3b43f 100644 --- a/packages/runtime-core/src/compat/compatConfig.ts +++ b/packages/runtime-core/src/compat/compatConfig.ts @@ -19,7 +19,7 @@ export interface ComponentOptionsCompat extends ComponentOptions { propsData?: any parent?: any - + __isBuildIn?: boolean } From e7c0383e28a649c8782e8c66800196f70de0811f Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 6 Nov 2023 17:22:06 +0000 Subject: [PATCH 05/79] add Extract component Options --- .../dts-test/componentTypeHelpers.test-d.ts | 168 +++++++++++++++--- packages/dts-test/defineComponent.test-d.tsx | 4 +- .../runtime-core/src/apiDefineComponent.ts | 127 +++---------- .../runtime-core/src/componentTypeHelpers.ts | 52 +++--- 4 files changed, 196 insertions(+), 155 deletions(-) diff --git a/packages/dts-test/componentTypeHelpers.test-d.ts b/packages/dts-test/componentTypeHelpers.test-d.ts index d3a97a53fb6..82b9a7224a5 100644 --- a/packages/dts-test/componentTypeHelpers.test-d.ts +++ b/packages/dts-test/componentTypeHelpers.test-d.ts @@ -1,30 +1,154 @@ -// import { expectType, describe } from './utils' +import { expectType, describe } from './utils' -// import { -// ExtractComponentOptions, -// ExtractComponentSlots, -// ExtractComponentEmits, -// defineComponent -// } from 'vue' +import { + ExtractComponentOptions, + ExtractComponentSlots, + ExtractComponentEmits, + defineComponent, + defineAsyncComponent +} from 'vue' -// describe('Extract Component Options', () => { -// describe('define Component', () => { -// // const comp = { -// // props: ['bar'] -// // } as const +declare function extractComponentOptions(comp: T): ExtractComponentOptions -// const Comp = defineComponent({ -// props: ['bar'] -// }) +declare function extractComponentSlots(comp: T): ExtractComponentSlots +describe('Extract Component Options', () => { + describe('defineComponent', () => { + const propsOptions = { + props: { + a: String, + b: Boolean, -// const a = {} as unknown as ExtractComponentOptions + bb: { + type: Boolean, + required: true + } + }, + slots: { + default(arg: { msg: string }) {} + }, + foo: 'bar', + data() { + return { + test: 1 + } + } + } + // Component with props + const CompProps = defineComponent(propsOptions) + expectType>(propsOptions) + // @ts-expect-error checking if is not any + expectType>({ bar: 'foo' }) -// a.props + // component array props + const arrayOptions = { + props: ['a', 'b', 'c'], + slots: { + default(arg: { msg: string }) {} + }, + foo: 'bar', + data() { + return { + test: 1 + } + } + } + const CompPropsArray = defineComponent(arrayOptions) + expectType>(arrayOptions) + // @ts-expect-error checking if is not any + expectType>({ bar: 'foo' }) -// // expectType>(comp) -// }) + // component no props + const noPropsOptions = { + slots: { + default(arg: { msg: string }) {} + }, + foo: 'bar', + data() { + return { + test: 1 + } + } + } + const CompNoProps = defineComponent(noPropsOptions) + expectType>(noPropsOptions) + // @ts-expect-error checking if is not any + expectType>({ bar: 'foo' }) + }) -// describe('async component', () => {}) + describe('async component', () => { + const Component = defineAsyncComponent({ + loader: () => + Promise.resolve( + defineComponent({ + foo: 'bar' + }) + ) + }) -// describe('options object', () => {}) -// }) + // NOTE not sure if this is the intention since Component.foo is undefined + expectType>({ + foo: 'bar' + }) + }) + + describe('options object', () => { + const propsOptions = { + props: { + a: String, + b: Boolean, + + bb: { + type: Boolean, + required: true + } + }, + slots: { + default(arg: { msg: string }) {} + }, + foo: 'bar', + data() { + return { + test: 1 + } + } + } + + // Component with props + expectType>(propsOptions) + // @ts-expect-error checking if is not any + expectType>({ bar: 'foo' }) + + // component array props + const arrayOptions = { + props: ['a', 'b', 'c'], + slots: { + default(arg: { msg: string }) {} + }, + foo: 'bar', + data() { + return { + test: 1 + } + } + } + expectType>(arrayOptions) + // @ts-expect-error checking if is not any + expectType>({ bar: 'foo' }) + + // component no props + const noPropsOptions = { + slots: { + default(arg: { msg: string }) {} + }, + foo: 'bar', + data() { + return { + test: 1 + } + } + } + expectType>(noPropsOptions) + // @ts-expect-error checking if is not any + expectType>({ bar: 'foo' }) + }) +}) diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index 4278050dd80..839db16be57 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -1358,12 +1358,12 @@ describe('function syntax w/ runtime props', () => { } ) + // @ts-expect-error string prop names don't match defineComponent( (_props: { msg: string }) => { return () => {} }, { - // @ts-expect-error string prop names don't match props: ['bar'] } ) @@ -1380,6 +1380,7 @@ describe('function syntax w/ runtime props', () => { } ) + // @ts-expect-error prop keys don't match defineComponent( (_props: { msg: string }, ctx) => { return () => {} @@ -1387,7 +1388,6 @@ describe('function syntax w/ runtime props', () => { { props: { msg: String, - // @ts-expect-error prop keys don't match bar: String } } diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index ab195109274..3ca493c070d 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -41,6 +41,8 @@ type ResolveProps = Readonly< > & ({} extends E ? {} : EmitsToProps) +export declare const RawOptionsSymbol: unique symbol + export type DefineComponent< PropsOrPropOptions = {}, RawBindings = {}, @@ -93,8 +95,9 @@ export type DefineComponent< S >, 'props' - > & { props: PropsOrPropOptions } & Omit & - PP + > & { props: PropsOrPropOptions } & Omit & { + [RawOptionsSymbol]: Options + } & PP // defineComponent is a utility that is primarily used for type inference // when declaring components. Type inference is provided in the component @@ -102,25 +105,6 @@ export type DefineComponent< // for TSX / manual render function / IDE support. // overload 1: direct setup function -export function defineComponent< - Props extends Record, - E extends EmitsOptions = {}, - EE extends string = string, - S extends SlotsType = {}, - Options = {} ->( - setup: ( - props: Props, - ctx: SetupContext - ) => RenderFunction | Promise, - options?: Options & - Pick & { - props?: (keyof Props)[] - emits?: E | EE[] - slots?: S - } -): (props: Props & EmitsToProps) => any - export function defineComponent< Props extends Record, E extends EmitsOptions = {}, @@ -137,54 +121,11 @@ export function defineComponent< slots?: S } ): (props: Props & EmitsToProps) => any - -// (uses user defined props interface) -export function defineComponent< - Props extends Record, - E extends EmitsOptions = {}, - EE extends string = string, - S extends SlotsType = {}, - Options = {} ->( - setup: ( - props: Props, - ctx: SetupContext - ) => RenderFunction | Promise, - options?: Options & - Pick & { - props?: (keyof Props)[] - emits?: E | EE[] - slots?: S - } -): DefineComponent< - Props & EmitsToProps, - {}, - {}, - {}, - {}, - {}, - {}, - E, - EE, - PublicProps, - ResolveProps, - ExtractDefaultPropTypes, - {}, - string, - S, - { - name: string - } & Options -> - -// extend({ name: options.name }, extraOptions, { setup: options }))() - export function defineComponent< Props extends Record, E extends EmitsOptions = {}, EE extends string = string, - S extends SlotsType = {}, - Options = {} + S extends SlotsType = {} >( setup: ( props: Props, @@ -195,26 +136,7 @@ export function defineComponent< emits?: E | EE[] slots?: S } -): DefineComponent< - Props & EmitsToProps, - {}, - {}, - {}, - {}, - {}, - {}, - E, - EE, - PublicProps, - ResolveProps, - ExtractDefaultPropTypes, - {}, - string, - S, - { - name: string - } & Options -> +): (props: Props & EmitsToProps) => any // overload 2: object format with no props // (uses user defined props interface) @@ -338,22 +260,24 @@ export function defineComponent< EE extends string = string, I extends ComponentInjectOptions = {}, II extends string = string, - S extends SlotsType = {} + S extends SlotsType = {}, + Options = {} >( - options: ComponentOptionsWithObjectProps< - PropsOptions, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - I, - II, - S - > + options: Options & + ComponentOptionsWithObjectProps< + PropsOptions, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S + > ): DefineComponent< PropsOptions, RawBindings, @@ -369,7 +293,8 @@ export function defineComponent< ExtractDefaultPropTypes, I, II, - S + S, + Options > // implementation, close to no-op diff --git a/packages/runtime-core/src/componentTypeHelpers.ts b/packages/runtime-core/src/componentTypeHelpers.ts index fbd4a9dfa52..518f074e83f 100644 --- a/packages/runtime-core/src/componentTypeHelpers.ts +++ b/packages/runtime-core/src/componentTypeHelpers.ts @@ -1,36 +1,28 @@ // import { DefineComponent } from './apiDefineComponent' -import { ComponentOptionsBase } from './componentOptions' +import { ComponentOptionsBase } from '.' +import { DefineComponent, RawOptionsSymbol } from './apiDefineComponent' +// import { ComponentOptionsBase } from './componentOptions' -export type ExtractComponentOptions = T extends ComponentOptionsBase< - infer Props, - infer RawBindings, - infer D, - infer C, - infer M, - infer Mixin, - infer Extends, - infer E, - infer EE, - infer Defaults, - infer I, - infer II, - infer S -> - ? ComponentOptionsBase< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - Defaults, - I, - II, - S +export type ExtractComponentOptions = T extends { + [RawOptionsSymbol]: infer Options +} + ? Options + : T extends ComponentOptionsBase< + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any > + ? T : never export type ComponentProps = {} From 5f86b19dec61b49ac1f2861d16f980f04906fc3d Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 6 Nov 2023 18:30:58 +0000 Subject: [PATCH 06/79] added types --- .../dts-test/componentTypeHelpers.test-d.ts | 218 +++++++++++------- packages/runtime-core/src/componentOptions.ts | 14 -- .../runtime-core/src/componentTypeHelpers.ts | 55 ++++- 3 files changed, 182 insertions(+), 105 deletions(-) diff --git a/packages/dts-test/componentTypeHelpers.test-d.ts b/packages/dts-test/componentTypeHelpers.test-d.ts index 82b9a7224a5..36edd117d7b 100644 --- a/packages/dts-test/componentTypeHelpers.test-d.ts +++ b/packages/dts-test/componentTypeHelpers.test-d.ts @@ -3,6 +3,7 @@ import { expectType, describe } from './utils' import { ExtractComponentOptions, ExtractComponentSlots, + ComponentProps, ExtractComponentEmits, defineComponent, defineAsyncComponent @@ -11,28 +12,60 @@ import { declare function extractComponentOptions(comp: T): ExtractComponentOptions declare function extractComponentSlots(comp: T): ExtractComponentSlots + +const propsOptions = { + props: { + a: String, + b: Boolean, + + bb: { + type: Boolean, + required: true + } + }, + slots: { + default(arg: { msg: string }) {} + }, + foo: 'bar', + data() { + return { + test: 1 + } + } +} as const + +const arrayOptions = { + props: ['a', 'b', 'c'], + slots: { + default(arg: { msg: string }) {} + }, + foo: 'bar', + data() { + return { + test: 1 + } + } +} as const + +const noPropsOptions = { + slots: { + default(arg: { msg: string }) {} + }, + foo: 'bar', + data() { + return { + test: 1 + } + } +} as const + +const mixIn = { + props: ['a1'], + mixins: [propsOptions, arrayOptions, noPropsOptions] +} as const + describe('Extract Component Options', () => { describe('defineComponent', () => { - const propsOptions = { - props: { - a: String, - b: Boolean, - - bb: { - type: Boolean, - required: true - } - }, - slots: { - default(arg: { msg: string }) {} - }, - foo: 'bar', - data() { - return { - test: 1 - } - } - } // Component with props const CompProps = defineComponent(propsOptions) expectType>(propsOptions) @@ -40,39 +73,21 @@ describe('Extract Component Options', () => { expectType>({ bar: 'foo' }) // component array props - const arrayOptions = { - props: ['a', 'b', 'c'], - slots: { - default(arg: { msg: string }) {} - }, - foo: 'bar', - data() { - return { - test: 1 - } - } - } const CompPropsArray = defineComponent(arrayOptions) expectType>(arrayOptions) // @ts-expect-error checking if is not any expectType>({ bar: 'foo' }) // component no props - const noPropsOptions = { - slots: { - default(arg: { msg: string }) {} - }, - foo: 'bar', - data() { - return { - test: 1 - } - } - } const CompNoProps = defineComponent(noPropsOptions) expectType>(noPropsOptions) // @ts-expect-error checking if is not any expectType>({ bar: 'foo' }) + + const Mixins = defineComponent(mixIn) + expectType>(mixIn) + // @ts-expect-error checking if is not any + expectType>(mixIn) }) describe('async component', () => { @@ -92,63 +107,92 @@ describe('Extract Component Options', () => { }) describe('options object', () => { - const propsOptions = { - props: { - a: String, - b: Boolean, - - bb: { - type: Boolean, - required: true - } - }, - slots: { - default(arg: { msg: string }) {} - }, - foo: 'bar', - data() { - return { - test: 1 - } - } - } - // Component with props expectType>(propsOptions) // @ts-expect-error checking if is not any expectType>({ bar: 'foo' }) // component array props - const arrayOptions = { - props: ['a', 'b', 'c'], - slots: { - default(arg: { msg: string }) {} - }, - foo: 'bar', - data() { - return { - test: 1 - } - } - } expectType>(arrayOptions) // @ts-expect-error checking if is not any expectType>({ bar: 'foo' }) // component no props - const noPropsOptions = { - slots: { - default(arg: { msg: string }) {} - }, - foo: 'bar', - data() { - return { - test: 1 - } - } - } expectType>(noPropsOptions) // @ts-expect-error checking if is not any expectType>({ bar: 'foo' }) }) }) + +describe('Component Props', () => { + describe('defineComponent', () => { + // Component with props + const CompProps = defineComponent(propsOptions) + const p = {} as ComponentProps<{ + props: ['a'] + + emits: { + foo: (a: { msg: string }) => true + } + }> + + if (p.a && p.onFoo) { + } + + expectType<{ + readonly a?: string | undefined + readonly b: boolean | undefined + readonly bb: boolean + }>({} as ComponentProps) + // @ts-expect-error checking if is not any + expectType<{ bar: string }>({} as ComponentProps) + + // component array props + const CompPropsArray = defineComponent(arrayOptions) + expectType>(arrayOptions) + + // extractComponentOptions(CompPropsArray) + const a = {} as ComponentProps + // @ts-expect-error checking if is not any + expectType>({ bar: 'foo' }) + + // component no props + const CompNoProps = defineComponent(noPropsOptions) + expectType>(noPropsOptions) + // @ts-expect-error checking if is not any + expectType>({ bar: 'foo' }) + }) + + describe('async component', () => { + const Component = defineAsyncComponent({ + loader: () => + Promise.resolve( + defineComponent({ + foo: 'bar' + }) + ) + }) + + // NOTE not sure if this is the intention since Component.foo is undefined + expectType>({ + foo: 'bar' + }) + }) + + describe('options object', () => { + // Component with props + expectType>(propsOptions) + // @ts-expect-error checking if is not any + expectType>({ bar: 'foo' }) + + // component array props + expectType>(arrayOptions) + // @ts-expect-error checking if is not any + expectType>({ bar: 'foo' }) + + // component no props + expectType>(noPropsOptions) + // @ts-expect-error checking if is not any + expectType>({ bar: 'foo' }) + }) +}) diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index e6a0616ded9..e4f1834dc6d 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -362,20 +362,6 @@ export type ComponentOptionsWithObjectProps< > > -// Props, -// RawBindings, -// D, -// C extends ComputedOptions, -// M extends MethodOptions, -// Mixin extends ComponentOptionsMixin, -// Extends extends ComponentOptionsMixin, -// E extends EmitsOptions, -// EE extends string = string, -// Defaults = {}, -// I extends ComponentInjectOptions = {}, -// II extends string = string, -// S extends SlotsType = {}, -// OriginalProps extends ComponentPropsOptions = {} export type ComponentOptions< Props = Record, RawBindings = any, diff --git a/packages/runtime-core/src/componentTypeHelpers.ts b/packages/runtime-core/src/componentTypeHelpers.ts index 518f074e83f..ef191aff64f 100644 --- a/packages/runtime-core/src/componentTypeHelpers.ts +++ b/packages/runtime-core/src/componentTypeHelpers.ts @@ -1,6 +1,8 @@ // import { DefineComponent } from './apiDefineComponent' -import { ComponentOptionsBase } from '.' +import { Props } from 'packages/server-renderer/src/render' +import { ComponentOptionsBase, ExtractPropTypes } from '.' import { DefineComponent, RawOptionsSymbol } from './apiDefineComponent' +import { EmitsOptions, EmitsToProps } from './componentEmits' // import { ComponentOptionsBase } from './componentOptions' export type ExtractComponentOptions = T extends { @@ -25,13 +27,58 @@ export type ExtractComponentOptions = T extends { ? T : never -export type ComponentProps = {} -export type ExtraComponentProp = {} +export type ComponentProps< + T, + excludeEmits extends boolean = false +> = (excludeEmits extends false ? ComponentEmits : {}) & + (ExtractComponentOptions extends { + props: infer P + } + ? P extends Array + ? V extends string + ? Readonly<{ [key in V]?: any }> + : {} + : ExtractPropTypes

+ : T extends ComponentOptionsBase< + infer P, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any + > + ? P + : {}) + +export type ExtractComponentProp = T extends { + [RawOptionsSymbol]: infer Options +} + ? Options + : T extends { props: infer P } + ? P + : T extends (props: infer P) => any + ? P + : T extends { new (): { $props: infer P } } + ? P + : {} export type ComponentSlots = {} export type ExtractComponentSlots = {} -export type ComponentEmits = {} +export type ComponentEmits = ExtractComponentOptions extends { + emits: infer E extends EmitsOptions +} + ? EmitsToProps + : T extends (props: any, opts: { emits: infer E extends EmitsOptions }) => any + ? EmitsToProps + : {} export type ExtractComponentEmits = {} export type ComponentInternalInstance = {} From 22c304cae1d1f7cb0d08fe17f238e65e49d9fd6c Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Wed, 8 Nov 2023 06:53:08 +0000 Subject: [PATCH 07/79] more tests --- packages/dts-test/component.test-d.ts | 23 ++- .../dts-test/componentTypeHelpers.test-d.ts | 93 ++++++---- .../runtime-core/src/apiDefineComponent.ts | 2 +- packages/runtime-core/src/componentOptions.ts | 4 +- .../runtime-core/src/componentTypeHelpers.ts | 165 ++++++++++++------ packages/runtime-dom/src/apiCustomElement.ts | 6 +- 6 files changed, 194 insertions(+), 99 deletions(-) diff --git a/packages/dts-test/component.test-d.ts b/packages/dts-test/component.test-d.ts index 5535419f198..a2e303656a3 100644 --- a/packages/dts-test/component.test-d.ts +++ b/packages/dts-test/component.test-d.ts @@ -8,7 +8,8 @@ import { FunctionalComponent, ComponentPublicInstance, toRefs, - SetupContext + SetupContext, + ComponentProps } from 'vue' import { describe, expectAssignable, expectType, IsAny } from './utils' @@ -20,6 +21,8 @@ declare function extractComponentOptions( setup: ShallowUnwrapRef } +declare function extractComponentProps(obj: T): ComponentProps + describe('object props', () => { interface ExpectedProps { a?: number | undefined @@ -167,7 +170,9 @@ describe('object props', () => { } }) - const { props, rawBindings, setup } = extractComponentOptions(MyComponent) + const { rawBindings, setup } = extractComponentOptions(MyComponent) + + const props = extractComponentProps(MyComponent) // props expectType(props.a) @@ -323,8 +328,9 @@ describe('object props', () => { } } as const - const { props, rawBindings, setup } = extractComponentOptions(MyComponent) + const { rawBindings, setup } = extractComponentOptions(MyComponent) + const props = extractComponentProps(MyComponent) // props expectType(props.a) expectType(props.b) @@ -341,7 +347,7 @@ describe('object props', () => { expectType(props.fff) expectType(props.hhh) expectType(props.ggg) - // expectType(props.ffff) // todo fix + expectType(props.ffff) expectType(props.validated) expectType(props.object) @@ -385,14 +391,15 @@ describe('array props', () => { } } - const { props, rawBindings, setup } = extractComponentOptions(MyComponent) + const { rawBindings, setup } = extractComponentOptions(MyComponent) + + const props = extractComponentProps(MyComponent) // @ts-expect-error props should be readonly props.a = 1 - // TODO infer the correct keys - // expectType(props.a) - // expectType(props.b) + expectType(props.a) + expectType(props.b) expectType(rawBindings.c) expectType(setup.c) diff --git a/packages/dts-test/componentTypeHelpers.test-d.ts b/packages/dts-test/componentTypeHelpers.test-d.ts index 36edd117d7b..acbebfdf041 100644 --- a/packages/dts-test/componentTypeHelpers.test-d.ts +++ b/packages/dts-test/componentTypeHelpers.test-d.ts @@ -1,3 +1,4 @@ +import { as } from 'vitest/dist/reporters-5f784f42.js' import { expectType, describe } from './utils' import { @@ -35,7 +36,7 @@ const propsOptions = { } as const const arrayOptions = { - props: ['a', 'b', 'c'], + props: ['a', 'b', 'c'] as const, slots: { default(arg: { msg: string }) {} }, @@ -45,7 +46,7 @@ const arrayOptions = { test: 1 } } -} as const +} const noPropsOptions = { slots: { @@ -59,10 +60,10 @@ const noPropsOptions = { } } as const -const mixIn = { - props: ['a1'], - mixins: [propsOptions, arrayOptions, noPropsOptions] -} as const +// const mixIn = { +// props: ['a1'], +// mixins: [propsOptions, arrayOptions, noPropsOptions] +// } describe('Extract Component Options', () => { describe('defineComponent', () => { @@ -84,10 +85,17 @@ describe('Extract Component Options', () => { // @ts-expect-error checking if is not any expectType>({ bar: 'foo' }) - const Mixins = defineComponent(mixIn) - expectType>(mixIn) + const Mixins = defineComponent({ + props: ['a1'], + mixins: [propsOptions, arrayOptions, noPropsOptions] + }) + + expectType>({ + props: ['a1'], + mixins: [propsOptions, arrayOptions, noPropsOptions] + }) // @ts-expect-error checking if is not any - expectType>(mixIn) + expectType>({ bar: 'foo' }) }) describe('async component', () => { @@ -128,17 +136,6 @@ describe('Component Props', () => { describe('defineComponent', () => { // Component with props const CompProps = defineComponent(propsOptions) - const p = {} as ComponentProps<{ - props: ['a'] - - emits: { - foo: (a: { msg: string }) => true - } - }> - - if (p.a && p.onFoo) { - } - expectType<{ readonly a?: string | undefined readonly b: boolean | undefined @@ -149,18 +146,29 @@ describe('Component Props', () => { // component array props const CompPropsArray = defineComponent(arrayOptions) - expectType>(arrayOptions) - - // extractComponentOptions(CompPropsArray) - const a = {} as ComponentProps + // aX + expectType<{ + readonly a?: any + readonly b?: any + readonly c?: any + }>({} as ComponentProps) // @ts-expect-error checking if is not any - expectType>({ bar: 'foo' }) + expectType<{ bar: 'foo' }>({} as ComponentProps) // component no props const CompNoProps = defineComponent(noPropsOptions) - expectType>(noPropsOptions) // @ts-expect-error checking if is not any - expectType>({ bar: 'foo' }) + expectType<{ bar: 'foo' }>({} as ComponentProps) + + const mixin = defineComponent({ + props: ['a1'], + mixins: [CompProps, CompPropsArray, CompNoProps] + }) + const a = {} as ComponentProps + // a.c + expectType<{ + a1?: any + }>({} as ComponentProps) }) describe('async component', () => { @@ -168,31 +176,40 @@ describe('Component Props', () => { loader: () => Promise.resolve( defineComponent({ - foo: 'bar' + props: { + foo: String + } }) ) }) // NOTE not sure if this is the intention since Component.foo is undefined - expectType>({ - foo: 'bar' - }) + expectType<{ + foo?: string | undefined + }>({} as ComponentProps) }) describe('options object', () => { - // Component with props - expectType>(propsOptions) + expectType<{ + readonly a?: string | undefined + readonly b: boolean | undefined + readonly bb: boolean + }>({} as ComponentProps) // @ts-expect-error checking if is not any - expectType>({ bar: 'foo' }) + expectType<{ bar: string }>({} as ComponentProps) // component array props - expectType>(arrayOptions) + expectType<{ + readonly a?: any + readonly b?: any + readonly c?: any + }>({} as ComponentProps) // @ts-expect-error checking if is not any - expectType>({ bar: 'foo' }) + expectType<{ bar: 'foo' }>({} as ComponentProps) // component no props - expectType>(noPropsOptions) + expectType<{}>({} as ComponentProps) // @ts-expect-error checking if is not any - expectType>({ bar: 'foo' }) + expectType<{ bar: 'foo' }>({} as ComponentProps) }) }) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 3ca493c070d..0f90470ab44 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -41,7 +41,7 @@ type ResolveProps = Readonly< > & ({} extends E ? {} : EmitsToProps) -export declare const RawOptionsSymbol: unique symbol +export declare const RawOptionsSymbol: '__rawOptions' export type DefineComponent< PropsOrPropOptions = {}, diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index e4f1834dc6d..f9a0a0cc49e 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -417,6 +417,8 @@ export type ComponentOptionsMixin = ComponentOptionsBase< any, any, any, + any, + any, any > @@ -480,7 +482,7 @@ interface LegacyOptions< II extends string > { compatConfig?: CompatConfig - props?: ComponentPropsOptions + props?: ComponentPropsOptions | Readonly // // allow any custom options // [key: string]: any diff --git a/packages/runtime-core/src/componentTypeHelpers.ts b/packages/runtime-core/src/componentTypeHelpers.ts index ef191aff64f..cb042f227b9 100644 --- a/packages/runtime-core/src/componentTypeHelpers.ts +++ b/packages/runtime-core/src/componentTypeHelpers.ts @@ -1,9 +1,10 @@ -// import { DefineComponent } from './apiDefineComponent' -import { Props } from 'packages/server-renderer/src/render' -import { ComponentOptionsBase, ExtractPropTypes } from '.' -import { DefineComponent, RawOptionsSymbol } from './apiDefineComponent' -import { EmitsOptions, EmitsToProps } from './componentEmits' -// import { ComponentOptionsBase } from './componentOptions' +import { ComponentOptionsBase, ComponentOptionsMixin } from './componentOptions' +import { RawOptionsSymbol } from './apiDefineComponent' +import { EmitFn, EmitsOptions, EmitsToProps } from './componentEmits' +import { ExtractPropTypes } from './componentProps' +import { Slot, Slots } from './componentSlots' +import { VNode } from '.' +import { IntersectionMixin, UnwrapMixinsType } from './componentPublicInstance' export type ExtractComponentOptions = T extends { [RawOptionsSymbol]: infer Options @@ -25,43 +26,15 @@ export type ExtractComponentOptions = T extends { any > ? T + : T extends { + props?: any + emits?: any + slots?: any + } + ? T : never -export type ComponentProps< - T, - excludeEmits extends boolean = false -> = (excludeEmits extends false ? ComponentEmits : {}) & - (ExtractComponentOptions extends { - props: infer P - } - ? P extends Array - ? V extends string - ? Readonly<{ [key in V]?: any }> - : {} - : ExtractPropTypes

- : T extends ComponentOptionsBase< - infer P, - any, - any, - any, - any, - any, - any, - any, - any, - any, - any, - any, - any - > - ? P - : {}) - -export type ExtractComponentProp = T extends { - [RawOptionsSymbol]: infer Options -} - ? Options - : T extends { props: infer P } +export type ExtractComponentProp = T extends { props: infer P } ? P : T extends (props: infer P) => any ? P @@ -69,19 +42,113 @@ export type ExtractComponentProp = T extends { ? P : {} -export type ComponentSlots = {} -export type ExtractComponentSlots = {} +export type ExtractComponentSlots = T extends { + [RawOptionsSymbol]: infer Options +} + ? Options + : T extends { slots: infer S extends Slots } + ? S + : T extends (props: any, opts: { slots: infer S extends Slots }) => any + ? S + : T extends { new (): { $slots: infer S extends Slots } } + ? S + : {} -export type ComponentEmits = ExtractComponentOptions extends { - emits: infer E extends EmitsOptions +export type ExtractComponentEmits = T extends { + [RawOptionsSymbol]: infer Options extends ComponentOptionsMixin } - ? EmitsToProps + ? Options['emits'] + : T extends { emits: infer E extends EmitsOptions } + ? E : T extends (props: any, opts: { emits: infer E extends EmitsOptions }) => any - ? EmitsToProps + ? E + : // : T extends { new (): { $emits: infer E extends EmitsOptions } } + // ? S + {} + +type ResolveMixin = [T] extends [ + Readonly< + ComponentOptionsBase< + any, + any, + any, + any, + any, + infer M, + infer E, + any, + any, + any, + any, + any, + any + > + > +] + ? IntersectionMixin & IntersectionMixin : {} -export type ExtractComponentEmits = {} + +type ResolveMixinProps = UnwrapMixinsType, 'P'> + +export type ComponentProps< + T, + excludeEmits extends boolean = false +> = (excludeEmits extends false + ? ExtractComponentEmits extends infer E extends EmitsOptions + ? {} extends E + ? unknown + : EmitsToProps + : unknown + : unknown) & + (ExtractComponentProp extends infer P + ? P extends Readonly> + ? [V] extends [string] + ? Readonly<{ [key in V]?: any }> + : {} + : ExtractPropTypes

+ : {}) & + // props to be omitted since it does not like of `readonly ['', '']` props + ResolveMixinProps> + +export type ComponentSlots = ExtractComponentSlots extends infer S extends + Slots + ? { + [K in keyof S]: S[K] extends Slot ? (arg: V) => VNode : never + } + : {} + +// export type ComponentEmits = ExtractComponentOptions extends { +// emits: infer E +// } +// ? E extends EmitsOptions +// ? EmitsToProps +// : {} +// : T extends (props: any, opts: { emits: infer E extends EmitsOptions }) => any +// ? EmitsToProps +// : {} + +export type ComponentEmits = ExtractComponentEmits extends infer E + ? {} extends E + ? () => void + : EmitFn + : () => void export type ComponentInternalInstance = {} export type ComponentInstance = {} -// export type ComponentExposed = {} +// type P = ComponentProps<{ +// props: readonly ['a'] +// emits: ['a'] +// }> + +// type AA = ComponentEmits<{ +// emits: { +// a: (a: string) => true +// } +// }> +// type AA1 = ComponentEmits< +// (props: {}, ctx: { emits: { a: (a: string) => true } }) => void +// > + +// type BB1 = ExtractComponentEmits<{}> +// type B1 = ComponentEmits<{}> diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index be91eb6a4b1..70f70eb8325 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -21,7 +21,8 @@ import { ConcreteComponent, ComponentOptions, ComponentInjectOptions, - SlotsType + SlotsType, + ComponentObjectPropsOptions } from '@vue/runtime-core' import { camelize, extend, hyphenate, isArray, toNumber } from '@vue/shared' import { hydrate, render } from '.' @@ -254,7 +255,8 @@ export class VueElement extends BaseClass { let numberProps if (props && !isArray(props)) { for (const key in props) { - const opt = props[key] + // isArray does not exclude `readonly string[]` type + const opt = (props as ComponentObjectPropsOptions)[key] if ( opt === Number || (opt && (opt as Record).type === Number) From c2c0958d4ddef88d148cac823db4b43be5f6f1f4 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Wed, 8 Nov 2023 07:55:59 +0000 Subject: [PATCH 08/79] working few things --- .../dts-test/componentTypeHelpers.test-d.ts | 40 +++++++++++++------ packages/runtime-core/src/componentOptions.ts | 5 +-- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/packages/dts-test/componentTypeHelpers.test-d.ts b/packages/dts-test/componentTypeHelpers.test-d.ts index acbebfdf041..b7445707b03 100644 --- a/packages/dts-test/componentTypeHelpers.test-d.ts +++ b/packages/dts-test/componentTypeHelpers.test-d.ts @@ -1,19 +1,12 @@ -import { as } from 'vitest/dist/reporters-5f784f42.js' import { expectType, describe } from './utils' import { ExtractComponentOptions, - ExtractComponentSlots, ComponentProps, - ExtractComponentEmits, defineComponent, defineAsyncComponent } from 'vue' -declare function extractComponentOptions(comp: T): ExtractComponentOptions - -declare function extractComponentSlots(comp: T): ExtractComponentSlots - const propsOptions = { props: { a: String, @@ -33,10 +26,11 @@ const propsOptions = { test: 1 } } -} as const +} const arrayOptions = { - props: ['a', 'b', 'c'] as const, + // preventing from set as readonly otherwise it breaks typing + props: ['a', 'b', 'c'] as ['a', 'b', 'c'], slots: { default(arg: { msg: string }) {} }, @@ -58,7 +52,7 @@ const noPropsOptions = { test: 1 } } -} as const +} // const mixIn = { // props: ['a1'], @@ -162,12 +156,19 @@ describe('Component Props', () => { const mixin = defineComponent({ props: ['a1'], - mixins: [CompProps, CompPropsArray, CompNoProps] + mixins: [CompProps, CompPropsArray, CompNoProps], + + setup(props) { + props.a, props.a1 + props.bb + } }) - const a = {} as ComponentProps - // a.c expectType<{ a1?: any + a?: any + b?: any + c?: any + bb: boolean }>({} as ComponentProps) }) @@ -211,5 +212,18 @@ describe('Component Props', () => { expectType<{}>({} as ComponentProps) // @ts-expect-error checking if is not any expectType<{ bar: 'foo' }>({} as ComponentProps) + + const mixin = { + props: ['a1'] as ['a1'], + // casting cost to keep the types + mixins: [propsOptions, arrayOptions, noPropsOptions] as const + } + expectType<{ + a1?: any + a?: any + b?: any + c?: any + bb: boolean + }>({} as ComponentProps) }) }) diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index f9a0a0cc49e..489cc767a56 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -482,10 +482,7 @@ interface LegacyOptions< II extends string > { compatConfig?: CompatConfig - props?: ComponentPropsOptions | Readonly - - // // allow any custom options - // [key: string]: any + props?: ComponentPropsOptions | Readonly // state // Limitation: we cannot expose RawBindings on the `this` context for data From 3fbfe6f83e9e70e741191e65af8996c9b4d20963 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Wed, 8 Nov 2023 09:02:08 +0000 Subject: [PATCH 09/79] cleanup --- .../dts-test/componentTypeHelpers.test-d.ts | 7 +- .../runtime-core/src/componentTypeHelpers.ts | 99 +++++++++---------- 2 files changed, 54 insertions(+), 52 deletions(-) diff --git a/packages/dts-test/componentTypeHelpers.test-d.ts b/packages/dts-test/componentTypeHelpers.test-d.ts index b7445707b03..161892380dc 100644 --- a/packages/dts-test/componentTypeHelpers.test-d.ts +++ b/packages/dts-test/componentTypeHelpers.test-d.ts @@ -4,7 +4,12 @@ import { ExtractComponentOptions, ComponentProps, defineComponent, - defineAsyncComponent + defineAsyncComponent, + ExtractComponentProp, + ExtractComponentSlots, + SlotsType, + ExtractComponentEmits, + ComponentSlots } from 'vue' const propsOptions = { diff --git a/packages/runtime-core/src/componentTypeHelpers.ts b/packages/runtime-core/src/componentTypeHelpers.ts index cb042f227b9..5b7c58a6b07 100644 --- a/packages/runtime-core/src/componentTypeHelpers.ts +++ b/packages/runtime-core/src/componentTypeHelpers.ts @@ -1,6 +1,11 @@ import { ComponentOptionsBase, ComponentOptionsMixin } from './componentOptions' import { RawOptionsSymbol } from './apiDefineComponent' -import { EmitFn, EmitsOptions, EmitsToProps } from './componentEmits' +import { + EmitFn, + EmitsOptions, + EmitsToProps, + ObjectEmitsOptions +} from './componentEmits' import { ExtractPropTypes } from './componentProps' import { Slot, Slots } from './componentSlots' import { VNode } from '.' @@ -42,29 +47,52 @@ export type ExtractComponentProp = T extends { props: infer P } ? P : {} -export type ExtractComponentSlots = T extends { - [RawOptionsSymbol]: infer Options -} - ? Options +export type ExtractComponentSlots = T extends ComponentOptionsBase< + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + infer S +> + ? S + : T extends { slots: infer S } + ? S : T extends { slots: infer S extends Slots } ? S - : T extends (props: any, opts: { slots: infer S extends Slots }) => any + : T extends (props: any, opts: { slots: infer S }) => any ? S : T extends { new (): { $slots: infer S extends Slots } } ? S : {} -export type ExtractComponentEmits = T extends { - [RawOptionsSymbol]: infer Options extends ComponentOptionsMixin -} - ? Options['emits'] +export type ExtractComponentEmits = T extends ComponentOptionsBase< + any, + any, + any, + any, + any, + any, + any, + infer E +> + ? 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 { new (): { $emits: infer E extends EmitsOptions } } - // ? S - {} + : {} type ResolveMixin = [T] extends [ Readonly< @@ -94,12 +122,12 @@ export type ComponentProps< T, excludeEmits extends boolean = false > = (excludeEmits extends false - ? ExtractComponentEmits extends infer E extends EmitsOptions - ? {} extends E - ? unknown - : EmitsToProps + ? ExtractComponentEmits extends infer E + ? E extends EmitsOptions + ? EmitsToProps + : unknown : unknown - : unknown) & + : {}) & (ExtractComponentProp extends infer P ? P extends Readonly> ? [V] extends [string] @@ -107,48 +135,17 @@ export type ComponentProps< : {} : ExtractPropTypes

: {}) & - // props to be omitted since it does not like of `readonly ['', '']` props + // props to be omitted since we don't need them here ResolveMixinProps> -export type ComponentSlots = ExtractComponentSlots extends infer S extends - Slots +export type ComponentSlots = ExtractComponentSlots extends infer S ? { [K in keyof S]: S[K] extends Slot ? (arg: V) => VNode : never } : {} -// export type ComponentEmits = ExtractComponentOptions extends { -// emits: infer E -// } -// ? E extends EmitsOptions -// ? EmitsToProps -// : {} -// : T extends (props: any, opts: { emits: infer E extends EmitsOptions }) => any -// ? EmitsToProps -// : {} - export type ComponentEmits = ExtractComponentEmits extends infer E ? {} extends E ? () => void : EmitFn : () => void - -export type ComponentInternalInstance = {} -export type ComponentInstance = {} - -// type P = ComponentProps<{ -// props: readonly ['a'] -// emits: ['a'] -// }> - -// type AA = ComponentEmits<{ -// emits: { -// a: (a: string) => true -// } -// }> -// type AA1 = ComponentEmits< -// (props: {}, ctx: { emits: { a: (a: string) => true } }) => void -// > - -// type BB1 = ExtractComponentEmits<{}> -// type B1 = ComponentEmits<{}> From 99e48a731e0f42c55a50e58acfafb2d52de505d3 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Wed, 8 Nov 2023 09:05:33 +0000 Subject: [PATCH 10/79] removed unused --- packages/dts-test/componentTypeHelpers.test-d.ts | 5 ----- packages/runtime-core/src/componentTypeHelpers.ts | 9 ++------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/dts-test/componentTypeHelpers.test-d.ts b/packages/dts-test/componentTypeHelpers.test-d.ts index 161892380dc..7377108cc3a 100644 --- a/packages/dts-test/componentTypeHelpers.test-d.ts +++ b/packages/dts-test/componentTypeHelpers.test-d.ts @@ -5,11 +5,6 @@ import { ComponentProps, defineComponent, defineAsyncComponent, - ExtractComponentProp, - ExtractComponentSlots, - SlotsType, - ExtractComponentEmits, - ComponentSlots } from 'vue' const propsOptions = { diff --git a/packages/runtime-core/src/componentTypeHelpers.ts b/packages/runtime-core/src/componentTypeHelpers.ts index 5b7c58a6b07..46f8a170c86 100644 --- a/packages/runtime-core/src/componentTypeHelpers.ts +++ b/packages/runtime-core/src/componentTypeHelpers.ts @@ -1,11 +1,6 @@ -import { ComponentOptionsBase, ComponentOptionsMixin } from './componentOptions' +import { ComponentOptionsBase } from './componentOptions' import { RawOptionsSymbol } from './apiDefineComponent' -import { - EmitFn, - EmitsOptions, - EmitsToProps, - ObjectEmitsOptions -} from './componentEmits' +import { EmitFn, EmitsOptions, EmitsToProps } from './componentEmits' import { ExtractPropTypes } from './componentProps' import { Slot, Slots } from './componentSlots' import { VNode } from '.' From 1ce7234199abfdc4534b3385a9e8a205a68f8e01 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:07:14 +0000 Subject: [PATCH 11/79] [autofix.ci] apply automated fixes --- packages/dts-test/componentTypeHelpers.test-d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dts-test/componentTypeHelpers.test-d.ts b/packages/dts-test/componentTypeHelpers.test-d.ts index 7377108cc3a..b7445707b03 100644 --- a/packages/dts-test/componentTypeHelpers.test-d.ts +++ b/packages/dts-test/componentTypeHelpers.test-d.ts @@ -4,7 +4,7 @@ import { ExtractComponentOptions, ComponentProps, defineComponent, - defineAsyncComponent, + defineAsyncComponent } from 'vue' const propsOptions = { From d88f7afbfd1ddf99ece22600e94fe3448a85d061 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Wed, 8 Nov 2023 14:09:01 +0000 Subject: [PATCH 12/79] remove stuff temp --- packages/dts-test/defineComponent.test-d.tsx | 23 ++++++++++---------- packages/runtime-core/src/component.ts | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index 839db16be57..0f94035eb06 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -291,17 +291,18 @@ describe('with object props', () => { /> ) - expectType( - ({ a: 'eee' })} - fff={(a, b) => ({ a: a > +b })} - hhh={false} - jjj={() => ''} - /> - ) + // TODO readd me!!!!!!!!!!! or fix + // expectType( + // ({ a: 'eee' })} + // fff={(a, b) => ({ a: a > +b })} + // hhh={false} + // jjj={() => ''} + // /> + // ) // @ts-expect-error missing required props let c = diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 41279124479..eaf22bd368e 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -180,7 +180,7 @@ export type Component< > = | ConcreteComponent | ComponentPublicInstanceConstructor - | ComponentPublicInstance + // | ComponentPublicInstance export type { ComponentOptions } From 3b653cd44ad11eaae7785ed539184e26a88a8d8f Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 14:10:06 +0000 Subject: [PATCH 13/79] [autofix.ci] apply automated fixes --- packages/runtime-core/src/component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index eaf22bd368e..d881e7f395f 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -180,7 +180,7 @@ export type Component< > = | ConcreteComponent | ComponentPublicInstanceConstructor - // | ComponentPublicInstance +// | ComponentPublicInstance export type { ComponentOptions } From 9b23cdf3c00a90560b5631d6d99561036058d38f Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Thu, 9 Nov 2023 09:58:48 +0000 Subject: [PATCH 14/79] small improvements --- packages/dts-built-test/src/index.ts | 25 +++++++++++- .../runtime-core/src/apiDefineComponent.ts | 5 ++- packages/runtime-core/src/componentOptions.ts | 38 +++++++++---------- 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/packages/dts-built-test/src/index.ts b/packages/dts-built-test/src/index.ts index 2d9d4033254..f333b831edf 100644 --- a/packages/dts-built-test/src/index.ts +++ b/packages/dts-built-test/src/index.ts @@ -1,10 +1,33 @@ -import { defineComponent } from 'vue' +import { PropType, defineComponent } from 'vue' const _CustomPropsNotErased = defineComponent({ props: {}, setup() {} }) +export const RegularComponent = defineComponent({ + props: { + // a: String + }, + setup(props) { + return () => {} + } +}) + +type MyInterface = + | { + a: string + } + | { b: string } +export const RegularComponentProps = defineComponent({ + props: { + a: Object as () => MyInterface, + b: Object as PropType + }, + setup(props) { + return () => {} + } +}) // #8376 export const CustomPropsNotErased = _CustomPropsNotErased as typeof _CustomPropsNotErased & { diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 0f90470ab44..1de42345676 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -261,7 +261,10 @@ export function defineComponent< I extends ComponentInjectOptions = {}, II extends string = string, S extends SlotsType = {}, - Options = {} + Options = {}, + Props = {} extends PropsOptions + ? {} + : PropsOptions >( options: Options & ComponentOptionsWithObjectProps< diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 489cc767a56..be7e27cb9bb 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -49,7 +49,6 @@ import { WritableComputedOptions } from '@vue/reactivity' import { - ComponentObjectPropsOptions, ExtractPropTypes, ExtractDefaultPropTypes, ComponentPropsOptions @@ -311,7 +310,7 @@ export type ComponentOptionsWithArrayProps< > export type ComponentOptionsWithObjectProps< - PropsOptions = ComponentObjectPropsOptions, + PropsOptions = ComponentPropsOptions, RawBindings = {}, D = {}, C extends ComputedOptions = {}, @@ -323,25 +322,24 @@ export type ComponentOptionsWithObjectProps< I extends ComponentInjectOptions = {}, II extends string = string, S extends SlotsType = {}, - Props = Prettify & EmitsToProps>>, + Props = {} extends PropsOptions + ? Prettify> + : Prettify & EmitsToProps>>, Defaults = ExtractDefaultPropTypes -> = Omit< - ComponentOptionsBase< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - Defaults, - I, - II, - S - >, - 'props' +> = ComponentOptionsBase< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + Defaults, + I, + II, + S > & { props: PropsOptions & ThisType } & ThisType< From 8b1faf7d45284adaf538dbfda94a04a1a5ab1760 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 10 Nov 2023 07:52:23 +0000 Subject: [PATCH 15/79] [autofix.ci] apply automated fixes --- packages/runtime-core/src/apiDefineComponent.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 3f31bdd8717..9b06f327e13 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -261,9 +261,7 @@ export function defineComponent< II extends string = string, S extends SlotsType = {}, Options = {}, - Props = {} extends PropsOptions - ? {} - : PropsOptions + Props = {} extends PropsOptions ? {} : PropsOptions >( options: Options & ComponentOptionsWithObjectProps< From ae7b51beb9a8c2e381348577cd38cb5fae9065d2 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Fri, 10 Nov 2023 10:49:20 +0000 Subject: [PATCH 16/79] export LooseRequired --- packages/runtime-core/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 188728a06b0..23ebe52f5f4 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -162,6 +162,7 @@ declare module '@vue/reactivity' { } export type * from './componentTypeHelpers' +export type { LooseRequired } from '@vue/shared' export { TrackOpTypes, TriggerOpTypes } from '@vue/reactivity' export type { From 9e67b17fde2f137fe4d346dd58f64a03c9d0bd52 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Mon, 13 Nov 2023 15:03:20 +0000 Subject: [PATCH 17/79] WIP DefineComponentOptions type --- packages/dts-test/defineComponent.test-d.tsx | 38 +- .../runtime-core/src/apiDefineComponent.ts | 625 ++++++++++++++---- packages/runtime-core/src/componentOptions.ts | 10 +- packages/runtime-core/src/componentProps.ts | 1 + .../runtime-core/src/componentTypeHelpers.ts | 235 ++++++- 5 files changed, 746 insertions(+), 163 deletions(-) diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index c99f96dee0b..20e23954865 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -319,11 +319,11 @@ describe('with object props', () => { props: { myProp: { type: Number, - validator(val: unknown): boolean { + validator: (val: unknown) => { // @ts-expect-error return val !== this.otherProp }, - default(): number { + default: () => { // @ts-expect-error return this.otherProp + 1 } @@ -336,23 +336,23 @@ describe('with object props', () => { }) }) -describe('type inference w/ optional props declaration', () => { - const MyComponent = defineComponent<{ a: string[]; msg: string }>({ - setup(props) { - expectType(props.msg) - expectType(props.a) - return { - b: 1 - } - } - }) - - expectType() - // @ts-expect-error - ; - // @ts-expect-error - ; -}) +// describe('type inference w/ optional props declaration', () => { +// const MyComponent = defineComponent<{ a: string[]; msg: string }>({ +// setup(props) { +// expectType(props.msg) +// expectType(props.a) +// return { +// b: 1 +// } +// } +// }) + +// expectType() +// // @ts-expect-error +// ; +// // @ts-expect-error +// ; +// }) describe('type inference w/ direct setup function', () => { const MyComponent = defineComponent((_props: { msg: string }) => () => {}) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 9b06f327e13..4b85b06103d 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -19,27 +19,40 @@ import { ExtractPropTypes, ComponentPropsOptions, ExtractDefaultPropTypes, - ComponentObjectPropsOptions + ComponentObjectPropsOptions, + Prop, + PropType } from './componentProps' import { EmitsOptions, EmitsToProps } from './componentEmits' -import { extend, isFunction } from '@vue/shared' +import { Prettify, extend, isFunction } from '@vue/shared' import { VNodeProps } from './vnode' import { CreateComponentPublicInstance, ComponentPublicInstanceConstructor } from './componentPublicInstance' import { SlotsType } from './componentSlots' +import { h } from '.' export type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps -type ResolveProps = Readonly< - PropsOrPropOptions extends ComponentPropsOptions - ? ExtractPropTypes - : PropsOrPropOptions -> & - ({} extends E ? {} : EmitsToProps) +// type ResolveProps = Readonly< +// PropsOrPropOptions extends ComponentObjectPropsOptions +// ? ExtractPropTypes +// : [PropsOrPropOptions] extends [string] +// ? Prettify< +// Readonly<{ [key in PropsOrPropOptions]?: any } & EmitsToProps> +// > & { aaaa: 1 } +// : never +// > & +// ({} extends E ? {} : EmitsToProps) + +type ResolveProps = [Props] extends [string] + ? Readonly<{ [key in Props]?: any } & EmitsToProps> + : [Props] extends [ComponentObjectPropsOptions] + ? Readonly> & EmitsToProps + : {} export declare const RawOptionsSymbol: '__rawOptions' @@ -97,6 +110,150 @@ export type DefineComponent< > & { props: PropsOrPropOptions } & Omit & { [RawOptionsSymbol]: Options } & PP +export type ComponentDefineOptions< + 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 = {} + // test stuff + // PropNames extends string = Props extends string ? Props : never, + // PropOptions extends ComponentObjectPropsOptions< + // Record + // > = ComponentObjectPropsOptions> +> = + | (Options & { + props?: [Props] extends [string] ? Array : Props + } & ([Props] extends [string] + ? ComponentOptionsWithArrayProps< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S + > + : [Props] extends [undefined] + ? { + props?: undefined + } & ComponentOptionsWithoutProps< + {}, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S + > + : { + props: ComponentObjectPropsOptions + } & (Props extends ComponentObjectPropsOptions + ? ComponentOptionsWithObjectProps< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S + > + : never))) + | ((( + props: Props, + ctx: SetupContext + ) => RenderFunction | Promise) & + Options) +// export type ComponentDefineOptions< +// Props = undefined, +// 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 = {} +// > = +// | (Options & +// (undefined extends Props +// ? ComponentOptionsWithoutProps< +// {}, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S +// > +// : [Props] extends [string] +// ? ComponentOptionsWithArrayProps< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S +// > +// : [Props] extends [Readonly] +// ? ComponentOptionsWithObjectProps< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S +// > +// : false)) +// | ((( +// props: Props, +// ctx: SetupContext +// ) => RenderFunction | Promise) & +// Options) // defineComponent is a utility that is primarily used for type inference // when declaring components. Type inference is provided in the component @@ -137,11 +294,168 @@ export function defineComponent< } ): (props: Props & EmitsToProps) => any -// overload 2: object format with no props -// (uses user defined props interface) -// return type is for Vetur and TSX support +// // overload 2: object format with no props +// // (uses user defined props interface) +// // return type is for Vetur and TSX support +// export function defineComponent< +// 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 = {} +// >( +// options: Options & +// ComponentOptionsWithoutProps< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S +// > +// ): DefineComponent< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// PublicProps, +// ResolveProps, +// ExtractDefaultPropTypes, +// I, +// II, +// S, +// Options +// > + +// // overload 3: object format with array props declaration +// // props inferred as { [key in PropNames]?: any } +// // return type is for Vetur and TSX support + +// export function defineComponent< +// PropNames extends string, +// 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, +// Props = Readonly<{ [key in PropNames]?: any }>, +// Options = {} +// >( +// options: Options & +// ComponentOptionsWithArrayProps< +// PropNames, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S +// > +// ): DefineComponent< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// PublicProps, +// ResolveProps, +// ExtractDefaultPropTypes, +// I, +// II, +// S, +// Options +// > + +// // overload 4: object format with object props declaration +// // see `ExtractPropTypes` in ./componentProps.ts +// export function defineComponent< +// // the Readonly constraint allows TS to treat the type of { required: true } +// // as constant instead of boolean. +// PropsOptions extends Readonly, +// 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 = {}, +// Props = {} extends PropsOptions ? {} : PropsOptions +// >( +// options: Options & +// ComponentOptionsWithObjectProps< +// PropsOptions, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S +// > +// ): DefineComponent< +// PropsOptions, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// PublicProps, +// ResolveProps, +// ExtractDefaultPropTypes, +// I, +// II, +// S, +// Options +// > + export function defineComponent< - Props = {}, + Props = undefined, RawBindings = {}, D = {}, C extends ComputedOptions = {}, @@ -155,77 +469,23 @@ export function defineComponent< S extends SlotsType = {}, Options = {} >( - options: Options & - ComponentOptionsWithoutProps< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - I, - II, - S - > -): DefineComponent< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - PublicProps, - ResolveProps, - ExtractDefaultPropTypes, - I, - II, - S, - Options -> - -// overload 3: object format with array props declaration -// props inferred as { [key in PropNames]?: any } -// return type is for Vetur and TSX support - -export function defineComponent< - PropNames extends string, - 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, - Props = Readonly<{ [key in PropNames]?: any }>, - Options = {} ->( - options: Options & - ComponentOptionsWithArrayProps< - PropNames, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - I, - II, - S - > + options: ComponentDefineOptions< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S, + Options + > ): DefineComponent< - Props, + [Props] extends [string] ? Props[] : undefined extends Props ? {} : Props, RawBindings, D, C, @@ -243,60 +503,6 @@ export function defineComponent< Options > -// overload 4: object format with object props declaration -// see `ExtractPropTypes` in ./componentProps.ts -export function defineComponent< - // the Readonly constraint allows TS to treat the type of { required: true } - // as constant instead of boolean. - PropsOptions extends Readonly, - 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 = {}, - Props = {} extends PropsOptions ? {} : PropsOptions ->( - options: Options & - ComponentOptionsWithObjectProps< - PropsOptions, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - I, - II, - S - > -): DefineComponent< - PropsOptions, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - PublicProps, - ResolveProps, - ExtractDefaultPropTypes, - I, - II, - S, - Options -> - // implementation, close to no-op /*! #__NO_SIDE_EFFECTS__ */ export function defineComponent(options: unknown, extraOptions?: unknown) { @@ -307,3 +513,150 @@ export function defineComponent(options: unknown, extraOptions?: unknown) { extend({ name: options.name }, extraOptions, { setup: options }))() : options } +// const a = defineComponent({ +// setup() { +// return () => h('div') +// } +// }) +const b = defineComponent({ + props: ['a', 'b'], + setup(props) { + props.a + } +}) +const { $props } = new b() +$props.a +$props.b +// @ts-expect-error +$props.c + +// const o = defineComponent({ +// props: { +// a: String, +// b: null, +// c: { +// type: String, +// required: true +// } +// }, +// setup(props) {}, +// ssss(props, _opo) { +// props.a, props.b, props.c +// _opo.a, _opo.b, _opo.c +// } +// }) + +const a = defineComponent({ + short: true, + props: { + a: Number + // bb: { + // testXXX: 1, + // validator(b: any) { + // return true + // } + // validator(b: unknown) { + // return true + // } + // type: String + // validator(b: unknown) { + // return true + // } + // validator: (b: unknown) => { + // return true + // } + // validator(b: string) { + // this. + // return true + // } + // // required should make property non-void + // b: { + // type: String, + // required: true as true + // }, + // e: Function, + // h: Boolean, + // j: Function as PropType string | undefined)>, + // // default value should infer type and make it non-void + // bb: { + // default: 'hello' + // }, + // bbb: { + // // Note: default function value requires arrow syntax + explicit + // // annotation + // default: (props: any) => (props.bb as string) || 'foo' + // }, + // bbbb: { + // type: String, + // default: undefined + // }, + // bbbbb: { + // type: String, + // default: () => undefined + // }, + // // explicit type casting + // cc: Array as PropType, + // // required + type casting + // dd: { + // type: Object as PropType<{ n: 1 }>, + // required: true as true + // }, + // // return type + // ee: Function as PropType<() => string>, + // // arguments + object return + // ff: Function as PropType<(a: number, b: string) => { a: boolean }>, + // // explicit type casting with constructor + // ccc: Array as () => string[], + // // required + constructor type casting + // ddd: { + // type: Array as () => string[], + // required: true as true + // }, + // // required + object return + // eee: { + // type: Function as PropType<() => { a: string }>, + // required: true as true + // }, + // // required + arguments + object return + // fff: { + // type: Function as PropType<(a: number, b: string) => { a: boolean }>, + // required: true as true + // }, + // hhh: { + // type: Boolean, + // required: true as true + // }, + // // default + type casting + // ggg: { + // type: String as PropType<'foo' | 'bar'>, + // default: 'foo' + // }, + // // default + function + // ffff: { + // type: Function as PropType<(a: number, b: string) => { a: boolean }>, + // default: (a: number, b: string) => ({ a: a > +b }) + // }, + // // union + function with different return types + // iii: Function as PropType<(() => string) | (() => number)>, + // // union + function with different args & same return type + // jjj: { + // type: Function as PropType< + // ((arg1: string) => string) | ((arg1: string, arg2: string) => string) + // >, + // required: true as true + // }, + // kkk: null, + // validated: { + // type: String, + // // validator requires explicit annotation + // validator: (val: unknown) => val !== '' + // }, + // date: Date, + // l: [Date], + // ll: [Date, Number], + // lll: [String, Number] + }, + setup(props, ctx) { + props.a + } +}) diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index be7e27cb9bb..06742745f38 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -51,7 +51,9 @@ import { import { ExtractPropTypes, ExtractDefaultPropTypes, - ComponentPropsOptions + ComponentPropsOptions, + ComponentObjectPropsOptions, + Prop } from './componentProps' import { EmitsOptions, EmitsToProps } from './componentEmits' import { Directive } from './directives' @@ -134,7 +136,7 @@ export interface ComponentOptionsBase< // the return expression contains reference to `this`. // Luckily `render()` doesn't need any arguments nor does it care about return // type. - render?: Function + render?: RenderFunction components?: Record directives?: Record inheritAttrs?: boolean @@ -310,7 +312,7 @@ export type ComponentOptionsWithArrayProps< > export type ComponentOptionsWithObjectProps< - PropsOptions = ComponentPropsOptions, + PropsOptions = {}, RawBindings = {}, D = {}, C extends ComputedOptions = {}, @@ -341,7 +343,7 @@ export type ComponentOptionsWithObjectProps< II, S > & { - props: PropsOptions & ThisType + props: PropsOptions & ThisType } & ThisType< CreateComponentPublicInstance< Props, diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index ab03fd3e9c6..8c9e6a4b8fc 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -61,6 +61,7 @@ export interface PropOptions { type?: PropType | true | null required?: boolean default?: D | DefaultFactory | null | undefined | object + // validator?: (this: void, value: unknown) => boolean validator?(value: unknown): boolean /** * @internal diff --git a/packages/runtime-core/src/componentTypeHelpers.ts b/packages/runtime-core/src/componentTypeHelpers.ts index 46f8a170c86..99b20403cc6 100644 --- a/packages/runtime-core/src/componentTypeHelpers.ts +++ b/packages/runtime-core/src/componentTypeHelpers.ts @@ -1,9 +1,25 @@ -import { ComponentOptionsBase } from './componentOptions' +import { + ComponentInjectOptions, + ComponentOptionsBase, + ComponentOptionsMixin, + ComponentOptionsWithArrayProps, + ComponentOptionsWithObjectProps, + ComponentOptionsWithoutProps, + ComputedOptions, + MethodOptions, + RenderFunction +} from './componentOptions' import { RawOptionsSymbol } from './apiDefineComponent' import { EmitFn, EmitsOptions, EmitsToProps } from './componentEmits' -import { ExtractPropTypes } from './componentProps' -import { Slot, Slots } from './componentSlots' -import { VNode } from '.' +import { + ComponentObjectPropsOptions, + ComponentPropsOptions, + ExtractPropTypes, + Prop, + PropType +} from './componentProps' +import { Slot, Slots, SlotsType } from './componentSlots' +import { SetupContext, VNode, h } from '.' import { IntersectionMixin, UnwrapMixinsType } from './componentPublicInstance' export type ExtractComponentOptions = T extends { @@ -144,3 +160,214 @@ export type ComponentEmits = ExtractComponentEmits extends infer E ? () => void : EmitFn : () => void + +// export type ComponentDefineOptions< +// // OriginalProps = never, +// 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 = {}, +// // test stuff +// // PropNames extends string = Props extends string ? Props : never, +// PropOptions extends ComponentObjectPropsOptions< +// Record +// > = ComponentObjectPropsOptions> +// > = +// | (Options & { +// props?: [Props] extends [string] ? Props[] : PropOptions +// // [K: string] :any +// } & (Props extends string +// ? ComponentOptionsWithArrayProps< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S +// > +// : [Props] extends [undefined] +// ? ComponentOptionsWithoutProps< +// {}, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S +// > +// : [Props] extends [ComponentObjectPropsOptions] +// ? ComponentOptionsWithObjectProps< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S +// > +// : never)) +// | ((( +// props: Props, +// ctx: SetupContext +// ) => RenderFunction | Promise) & +// Options) + +// declare function supa< +// Props = undefined, +// 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 = {} +// >( +// options: ComponentDefineOptions< +// Props, +// RawBindings, +// D, +// C, +// M, +// Mixin, +// Extends, +// E, +// EE, +// I, +// II, +// S, +// Options +// > +// ): Options + +// const a = supa({ +// NonExistentOption: 'assa', +// setup(props) {} +// }) + +// const e = supa({}) + +// const b = supa({ +// props: ['a'], +// setup(props) { +// props.a +// //@ts-expect-error +// props.b +// } +// }) + +// const c = supa({ +// props: { +// a: String, +// b: { +// type: String, +// required: true +// } +// }, +// setup(props) { +// props.a +// props.b +// //@ts-expect-error +// props.c +// } +// }) + +// const f = supa(() => () => '') +// const aa = supa({ +// // props: undefined, +// // props: undefined as never, +// setup(props) { +// return () => h('div') +// } +// }) + +// const v = supa({ +// props: { +// a: String, +// aa: null, +// b: { +// type: String, +// required: true, +// validator: (b: unknown) => { +// // this. +// return true +// } +// }, +// c: { +// type: Boolean +// // validator(b: unknown) { +// // return false +// // } +// } +// // d: { +// // type: String, +// // validator(b: unknown): boolean { +// // return false +// // }, +// // required: true +// // } +// }, +// setup(props) { +// props.b, props.c +// }, +// ssss(p, c) { +// c +// } +// }) + +// const pp = ComponentObjectProps({ +// props: { +// a: String, +// b: { +// type: String, +// validator(b) { +// return true +// } +// } +// } +// }) + +// declare function propValidation(options: ComponentObjectPropsOptions): T + +// propValidation({ +// a: String, +// b: { +// type: String, +// validator(b) { +// return true +// } +// } +// }) + +// declare function ComponentObjectProps( +// options: ComponentOptionsWithObjectProps +// ): T From f6f82fa0ad80c416b3c8b9206560dd421316b891 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Tue, 14 Nov 2023 08:47:53 +0000 Subject: [PATCH 18/79] WIP building --- packages/dts-test/defineComponent.test-d.tsx | 4 +- .../runtime-core/src/apiDefineComponent.ts | 168 ++---------------- packages/runtime-core/src/component.ts | 3 +- packages/runtime-core/src/componentOptions.ts | 6 +- .../runtime-core/src/componentTypeHelpers.ts | 24 +-- 5 files changed, 21 insertions(+), 184 deletions(-) diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index 20e23954865..74355aea150 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -355,7 +355,9 @@ describe('with object props', () => { // }) describe('type inference w/ direct setup function', () => { - const MyComponent = defineComponent((_props: { msg: string }) => () => {}) + const MyComponent = defineComponent( + (_props: { msg: string }) => () => h('div') + ) expectType() // @ts-expect-error ; diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 4b85b06103d..f1c4b9ecc42 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -17,21 +17,17 @@ import { } from './component' import { ExtractPropTypes, - ComponentPropsOptions, ExtractDefaultPropTypes, - ComponentObjectPropsOptions, - Prop, - PropType + ComponentObjectPropsOptions } from './componentProps' import { EmitsOptions, EmitsToProps } from './componentEmits' -import { Prettify, extend, isFunction } from '@vue/shared' +import { extend, isFunction } from '@vue/shared' import { VNodeProps } from './vnode' import { CreateComponentPublicInstance, ComponentPublicInstanceConstructor } from './componentPublicInstance' import { SlotsType } from './componentSlots' -import { h } from '.' export type PublicProps = VNodeProps & AllowedComponentProps & @@ -48,11 +44,14 @@ export type PublicProps = VNodeProps & // > & // ({} extends E ? {} : EmitsToProps) -type ResolveProps = [Props] extends [string] - ? Readonly<{ [key in Props]?: any } & EmitsToProps> - : [Props] extends [ComponentObjectPropsOptions] - ? Readonly> & EmitsToProps - : {} +type ResolveProps = Readonly< + ([Props] extends [string] + ? { [key in Props]?: any } + : [Props] extends [ComponentObjectPropsOptions] + ? ExtractPropTypes + : {}) & + ({} extends E ? {} : EmitsToProps) +> export declare const RawOptionsSymbol: '__rawOptions' @@ -513,150 +512,3 @@ export function defineComponent(options: unknown, extraOptions?: unknown) { extend({ name: options.name }, extraOptions, { setup: options }))() : options } -// const a = defineComponent({ -// setup() { -// return () => h('div') -// } -// }) -const b = defineComponent({ - props: ['a', 'b'], - setup(props) { - props.a - } -}) -const { $props } = new b() -$props.a -$props.b -// @ts-expect-error -$props.c - -// const o = defineComponent({ -// props: { -// a: String, -// b: null, -// c: { -// type: String, -// required: true -// } -// }, -// setup(props) {}, -// ssss(props, _opo) { -// props.a, props.b, props.c -// _opo.a, _opo.b, _opo.c -// } -// }) - -const a = defineComponent({ - short: true, - props: { - a: Number - // bb: { - // testXXX: 1, - // validator(b: any) { - // return true - // } - // validator(b: unknown) { - // return true - // } - // type: String - // validator(b: unknown) { - // return true - // } - // validator: (b: unknown) => { - // return true - // } - // validator(b: string) { - // this. - // return true - // } - // // required should make property non-void - // b: { - // type: String, - // required: true as true - // }, - // e: Function, - // h: Boolean, - // j: Function as PropType string | undefined)>, - // // default value should infer type and make it non-void - // bb: { - // default: 'hello' - // }, - // bbb: { - // // Note: default function value requires arrow syntax + explicit - // // annotation - // default: (props: any) => (props.bb as string) || 'foo' - // }, - // bbbb: { - // type: String, - // default: undefined - // }, - // bbbbb: { - // type: String, - // default: () => undefined - // }, - // // explicit type casting - // cc: Array as PropType, - // // required + type casting - // dd: { - // type: Object as PropType<{ n: 1 }>, - // required: true as true - // }, - // // return type - // ee: Function as PropType<() => string>, - // // arguments + object return - // ff: Function as PropType<(a: number, b: string) => { a: boolean }>, - // // explicit type casting with constructor - // ccc: Array as () => string[], - // // required + constructor type casting - // ddd: { - // type: Array as () => string[], - // required: true as true - // }, - // // required + object return - // eee: { - // type: Function as PropType<() => { a: string }>, - // required: true as true - // }, - // // required + arguments + object return - // fff: { - // type: Function as PropType<(a: number, b: string) => { a: boolean }>, - // required: true as true - // }, - // hhh: { - // type: Boolean, - // required: true as true - // }, - // // default + type casting - // ggg: { - // type: String as PropType<'foo' | 'bar'>, - // default: 'foo' - // }, - // // default + function - // ffff: { - // type: Function as PropType<(a: number, b: string) => { a: boolean }>, - // default: (a: number, b: string) => ({ a: a > +b }) - // }, - // // union + function with different return types - // iii: Function as PropType<(() => string) | (() => number)>, - // // union + function with different args & same return type - // jjj: { - // type: Function as PropType< - // ((arg1: string) => string) | ((arg1: string, arg2: string) => string) - // >, - // required: true as true - // }, - // kkk: null, - // validated: { - // type: String, - // // validator requires explicit annotation - // validator: (val: unknown) => val !== '' - // }, - // date: Date, - // l: [Date], - // ll: [Date, Number], - // lll: [String, Number] - }, - setup(props, ctx) { - props.a - } -}) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index d881e7f395f..e67b0079d63 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -164,7 +164,8 @@ export type ConcreteComponent< I extends ComponentInjectOptions = any, S extends SlotsType = any > = - | ComponentOptions + | (ComponentOptions & + Record) | FunctionalComponent /** diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 06742745f38..a9738aeb882 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -51,9 +51,7 @@ import { import { ExtractPropTypes, ExtractDefaultPropTypes, - ComponentPropsOptions, - ComponentObjectPropsOptions, - Prop + ComponentPropsOptions } from './componentProps' import { EmitsOptions, EmitsToProps } from './componentEmits' import { Directive } from './directives' @@ -136,7 +134,7 @@ export interface ComponentOptionsBase< // the return expression contains reference to `this`. // Luckily `render()` doesn't need any arguments nor does it care about return // type. - render?: RenderFunction + render?: Function components?: Record directives?: Record inheritAttrs?: boolean diff --git a/packages/runtime-core/src/componentTypeHelpers.ts b/packages/runtime-core/src/componentTypeHelpers.ts index 99b20403cc6..bbe94633fbd 100644 --- a/packages/runtime-core/src/componentTypeHelpers.ts +++ b/packages/runtime-core/src/componentTypeHelpers.ts @@ -1,25 +1,9 @@ -import { - ComponentInjectOptions, - ComponentOptionsBase, - ComponentOptionsMixin, - ComponentOptionsWithArrayProps, - ComponentOptionsWithObjectProps, - ComponentOptionsWithoutProps, - ComputedOptions, - MethodOptions, - RenderFunction -} from './componentOptions' +import { ComponentOptionsBase } from './componentOptions' import { RawOptionsSymbol } from './apiDefineComponent' import { EmitFn, EmitsOptions, EmitsToProps } from './componentEmits' -import { - ComponentObjectPropsOptions, - ComponentPropsOptions, - ExtractPropTypes, - Prop, - PropType -} from './componentProps' -import { Slot, Slots, SlotsType } from './componentSlots' -import { SetupContext, VNode, h } from '.' +import { ExtractPropTypes } from './componentProps' +import { Slot, Slots } from './componentSlots' +import { VNode } from '.' import { IntersectionMixin, UnwrapMixinsType } from './componentPublicInstance' export type ExtractComponentOptions = T extends { From 0506beb1c04849e08c45372bf93e56951bdff729 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Tue, 14 Nov 2023 08:54:46 +0000 Subject: [PATCH 19/79] test passing --- packages/dts-test/defineComponent.test-d.tsx | 1 + packages/runtime-core/src/component.ts | 3 ++- packages/runtime-core/src/componentOptions.ts | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index 74355aea150..e6c4df5f194 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -1202,6 +1202,7 @@ describe('DefineComponent should infer correct types when assigning to Component expectType<[]>(slots) } }) + expectType(component) }) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index e67b0079d63..4a24944b6dc 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -181,7 +181,8 @@ export type Component< > = | ConcreteComponent | ComponentPublicInstanceConstructor -// | ComponentPublicInstance + // | Record + | ComponentPublicInstance export type { ComponentOptions } diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index a9738aeb882..3b677351e6b 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -134,7 +134,7 @@ export interface ComponentOptionsBase< // the return expression contains reference to `this`. // Luckily `render()` doesn't need any arguments nor does it care about return // type. - render?: Function + render?: Function | ((...args: any[]) => any) components?: Record directives?: Record inheritAttrs?: boolean From 3e29651cdf5315e13f1ae6229225d45d852083f3 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Tue, 14 Nov 2023 09:20:48 +0000 Subject: [PATCH 20/79] fix other issues --- packages/dts-test/defineComponent.test-d.tsx | 64 ++++++----- .../runtime-core/src/apiDefineComponent.ts | 105 +++++++++--------- 2 files changed, 84 insertions(+), 85 deletions(-) diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index e6c4df5f194..f86cbae593e 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -291,18 +291,17 @@ describe('with object props', () => { /> ) - // TODO readd me!!!!!!!!!!! or fix - // expectType( - // ({ a: 'eee' })} - // fff={(a, b) => ({ a: a > +b })} - // hhh={false} - // jjj={() => ''} - // /> - // ) + expectType( + ({ a: 'eee' })} + fff={(a, b) => ({ a: a > +b })} + hhh={false} + jjj={() => ''} + /> + ) // @ts-expect-error missing required props let c = @@ -336,23 +335,23 @@ describe('with object props', () => { }) }) -// describe('type inference w/ optional props declaration', () => { -// const MyComponent = defineComponent<{ a: string[]; msg: string }>({ -// setup(props) { -// expectType(props.msg) -// expectType(props.a) -// return { -// b: 1 -// } -// } -// }) - -// expectType() -// // @ts-expect-error -// ; -// // @ts-expect-error -// ; -// }) +describe('type inference w/ optional props declaration', () => { + const MyComponent = defineComponent<{ a: string[]; msg: string }>({ + setup(props) { + expectType(props.msg) + expectType(props.a) + return { + b: 1 + } + } + }) + + expectType() + // @ts-expect-error + ; + // @ts-expect-error + ; +}) describe('type inference w/ direct setup function', () => { const MyComponent = defineComponent( @@ -1258,10 +1257,6 @@ describe('prop starting with `on*` is broken', () => { }) describe('function syntax w/ generics', () => { - const aa = defineComponent((props: { msg: T }) => { - return () => h('div') - }) - const Comp = defineComponent( // TODO: babel plugin to auto infer runtime props options from type // similar to defineProps<{...}>() @@ -1504,6 +1499,9 @@ describe('should work when props type is incompatible with setup returned type ' expectType(CompA) expectType(CompA.size) expectType(CompA.$props.size) + + const temp = {} as DefineComponent<{ size: SizeType }> + new temp().$props.size }) import { diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index f1c4b9ecc42..a7d5068c1d1 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -49,7 +49,7 @@ type ResolveProps = Readonly< ? { [key in Props]?: any } : [Props] extends [ComponentObjectPropsOptions] ? ExtractPropTypes - : {}) & + : Props) & ({} extends E ? {} : EmitsToProps) > @@ -186,6 +186,7 @@ export type ComponentDefineOptions< ctx: SetupContext ) => RenderFunction | Promise) & Options) + // export type ComponentDefineOptions< // Props = undefined, // RawBindings = {}, @@ -293,57 +294,57 @@ export function defineComponent< } ): (props: Props & EmitsToProps) => any -// // overload 2: object format with no props -// // (uses user defined props interface) -// // return type is for Vetur and TSX support -// export function defineComponent< -// 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 = {} -// >( -// options: Options & -// ComponentOptionsWithoutProps< -// Props, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// I, -// II, -// S -// > -// ): DefineComponent< -// Props, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// PublicProps, -// ResolveProps, -// ExtractDefaultPropTypes, -// I, -// II, -// S, -// Options -// > +// overload 2: object format with no props +// (uses user defined props interface) +// return type is for Vetur and TSX support +export function defineComponent< + 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 = {} +>( + options: Options & + ComponentOptionsWithoutProps< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S + > +): DefineComponent< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + PublicProps, + ResolveProps, + ExtractDefaultPropTypes, + I, + II, + S, + Options +> // // overload 3: object format with array props declaration // // props inferred as { [key in PropNames]?: any } From 48a0b0871cc8e7797f5603092f6f3a79ae817b3c Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Tue, 14 Nov 2023 09:37:09 +0000 Subject: [PATCH 21/79] remove render function type --- packages/dts-test/defineComponent.test-d.tsx | 44 +++++++++++++++++-- packages/runtime-core/src/componentOptions.ts | 2 +- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index f86cbae593e..36f8eb0e4d6 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -193,7 +193,7 @@ describe('with object props', () => { provide() { return {} }, - render() { + render(): null { const props = this.$props expectType(props.a) expectType(props.b) @@ -576,7 +576,7 @@ describe('with mixins', () => { expectType(props.bP2) expectType(props.z) }, - render() { + render(): null { const props = this.$props // props expectType<((...args: any[]) => any) | undefined>(props.onClick) @@ -671,7 +671,7 @@ describe('with extends', () => { required: true } }, - render() { + render(): null { const props = this.$props // props expectType(props.aP1) @@ -762,7 +762,7 @@ describe('extends with mixins', () => { required: true } }, - render() { + render(): null { const props = this.$props // props expectType<((...args: any[]) => any) | undefined>(props.onClick) @@ -1532,3 +1532,39 @@ declare const MyButton: DefineComponent< {} > ; + +// match return type of router.resolve: RouteLocation & { href: string } +const defaultRoute = { + path: '/', + name: undefined as string | undefined, + redirectedFrom: undefined as object | undefined, + params: {}, + query: {}, + hash: '', + fullPath: '/', + matched: [] as object[], + meta: {}, + href: '/' +} + +// TODO: Borrow typings from vue-router-next +export const RouterLinkStub = defineComponent({ + name: 'RouterLinkStub', + + compatConfig: { MODE: 3 }, + + props: { + to: { + type: [String, Object], + required: true + }, + custom: { + type: Boolean, + default: false + } + }, + + render() { + return this.custom ? {} : {} + } +}) diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 3b677351e6b..a9738aeb882 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -134,7 +134,7 @@ export interface ComponentOptionsBase< // the return expression contains reference to `this`. // Luckily `render()` doesn't need any arguments nor does it care about return // type. - render?: Function | ((...args: any[]) => any) + render?: Function components?: Record directives?: Record inheritAttrs?: boolean From 6d1db29c49786e17a0fd6719e5c9e7040c91bf6b Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Tue, 14 Nov 2023 09:54:20 +0000 Subject: [PATCH 22/79] async component changes --- .../dts-test/componentTypeHelpers.test-d.ts | 28 +++++---- packages/dts-test/defineComponent.test-d.tsx | 58 ++++--------------- packages/runtime-core/src/component.ts | 2 +- 3 files changed, 25 insertions(+), 63 deletions(-) diff --git a/packages/dts-test/componentTypeHelpers.test-d.ts b/packages/dts-test/componentTypeHelpers.test-d.ts index b7445707b03..fb49c625ee0 100644 --- a/packages/dts-test/componentTypeHelpers.test-d.ts +++ b/packages/dts-test/componentTypeHelpers.test-d.ts @@ -92,21 +92,19 @@ describe('Extract Component Options', () => { expectType>({ bar: 'foo' }) }) - describe('async component', () => { - const Component = defineAsyncComponent({ - loader: () => - Promise.resolve( - defineComponent({ - foo: 'bar' - }) - ) - }) - - // NOTE not sure if this is the intention since Component.foo is undefined - expectType>({ - foo: 'bar' - }) - }) + // describe('async component', () => { + // const Component = defineAsyncComponent({ + // loader: () => + // Promise.resolve( + // defineComponent({ + // foo: 'bar' + // }) + // ) + // }) + + // // NOTE not sure if this is the intention since Component.foo is undefined + // expectType>({}) + // }) describe('options object', () => { // Component with props diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index 36f8eb0e4d6..ee110325496 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -291,17 +291,17 @@ describe('with object props', () => { /> ) - expectType( - ({ a: 'eee' })} - fff={(a, b) => ({ a: a > +b })} - hhh={false} - jjj={() => ''} - /> - ) + // expectType( + // ({ a: 'eee' })} + // fff={(a, b) => ({ a: a > +b })} + // hhh={false} + // jjj={() => ''} + // /> + // ) // @ts-expect-error missing required props let c = @@ -1532,39 +1532,3 @@ declare const MyButton: DefineComponent< {} > ; - -// match return type of router.resolve: RouteLocation & { href: string } -const defaultRoute = { - path: '/', - name: undefined as string | undefined, - redirectedFrom: undefined as object | undefined, - params: {}, - query: {}, - hash: '', - fullPath: '/', - matched: [] as object[], - meta: {}, - href: '/' -} - -// TODO: Borrow typings from vue-router-next -export const RouterLinkStub = defineComponent({ - name: 'RouterLinkStub', - - compatConfig: { MODE: 3 }, - - props: { - to: { - type: [String, Object], - required: true - }, - custom: { - type: Boolean, - default: false - } - }, - - render() { - return this.custom ? {} : {} - } -}) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 4a24944b6dc..af2901c9a3a 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -182,7 +182,7 @@ export type Component< | ConcreteComponent | ComponentPublicInstanceConstructor // | Record - | ComponentPublicInstance + // | ComponentPublicInstance export type { ComponentOptions } From f47bc76c2cd9ef6fd8c15c1a5b9bcf991975175d Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 09:55:20 +0000 Subject: [PATCH 23/79] [autofix.ci] apply automated fixes --- packages/runtime-core/src/component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index af2901c9a3a..1cb52dd1069 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -181,8 +181,8 @@ export type Component< > = | ConcreteComponent | ComponentPublicInstanceConstructor - // | Record - // | ComponentPublicInstance +// | Record +// | ComponentPublicInstance export type { ComponentOptions } From bbad2f85e63ce44e6c9acc4560b133c55aadf518 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Tue, 14 Nov 2023 15:27:16 +0000 Subject: [PATCH 24/79] support more overloads on defineComponet and also support VNode on h --- packages/dts-test/defineComponent.test-d.tsx | 12 +- packages/dts-test/h.test-d.ts | 4 + .../runtime-core/src/apiDefineComponent.ts | 112 +++++++++++++----- packages/runtime-core/src/apiSetupHelpers.ts | 3 +- packages/runtime-core/src/componentProps.ts | 4 +- packages/runtime-core/src/h.ts | 8 ++ packages/runtime-core/src/index.ts | 2 +- 7 files changed, 107 insertions(+), 38 deletions(-) diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index ee110325496..8c33adf3f11 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -11,7 +11,9 @@ import { h, SlotsType, Slots, - VNode + VNode, + ComponentPropsOptions, + ComponentObjectPropsOptions } from 'vue' import { describe, expectType, IsUnion } from './utils' @@ -1532,3 +1534,11 @@ declare const MyButton: DefineComponent< {} > ; + +defineComponent({ + props: {} as ComponentPropsOptions, + + emits: ['a'], + + setup(props) {} +}) diff --git a/packages/dts-test/h.test-d.ts b/packages/dts-test/h.test-d.ts index 47ed62709c9..0e4af50a51c 100644 --- a/packages/dts-test/h.test-d.ts +++ b/packages/dts-test/h.test-d.ts @@ -253,3 +253,7 @@ describe('h should work with multiple types', () => { h(sampleComponent, {}) h(sampleComponent, {}, []) }) + +describe('should allow to assign vnode', () => { + h(h('div', 'test')) +}) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index a7d5068c1d1..8b8c2a20b2f 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -15,10 +15,9 @@ import { AllowedComponentProps, ComponentCustomProps } from './component' -import { +import ComponentObjectPropsOptions, { ExtractPropTypes, - ExtractDefaultPropTypes, - ComponentObjectPropsOptions + ExtractDefaultPropTypes } from './componentProps' import { EmitsOptions, EmitsToProps } from './componentEmits' import { extend, isFunction } from '@vue/shared' @@ -33,17 +32,6 @@ export type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps -// type ResolveProps = Readonly< -// PropsOrPropOptions extends ComponentObjectPropsOptions -// ? ExtractPropTypes -// : [PropsOrPropOptions] extends [string] -// ? Prettify< -// Readonly<{ [key in PropsOrPropOptions]?: any } & EmitsToProps> -// > & { aaaa: 1 } -// : never -// > & -// ({} extends E ? {} : EmitsToProps) - type ResolveProps = Readonly< ([Props] extends [string] ? { [key in Props]?: any } @@ -163,24 +151,34 @@ export type ComponentDefineOptions< II, S > - : { - props: ComponentObjectPropsOptions - } & (Props extends ComponentObjectPropsOptions - ? ComponentOptionsWithObjectProps< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - I, - II, - S - > - : never))) + : Props extends ComponentObjectPropsOptions + ? ComponentOptionsWithObjectProps< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S + > + : // adding support for ComponentOProp + ComponentOptions< + Readonly & EmitsToProps>, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + I, + S + >)) | ((( props: Props, ctx: SetupContext @@ -503,6 +501,56 @@ export function defineComponent< Options > +// Overload for {props: ComponentPropsOptions} +export function defineComponent< + 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 = {} +>( + options: Options & + ComponentOptionsWithObjectProps< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S + > +): DefineComponent< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + PublicProps, + ResolveProps, + ExtractDefaultPropTypes, + I, + II, + S, + Options +> + // implementation, close to no-op /*! #__NO_SIDE_EFFECTS__ */ export function defineComponent(options: unknown, extraOptions?: unknown) { diff --git a/packages/runtime-core/src/apiSetupHelpers.ts b/packages/runtime-core/src/apiSetupHelpers.ts index 509c280d63b..95fdd1a2ab3 100644 --- a/packages/runtime-core/src/apiSetupHelpers.ts +++ b/packages/runtime-core/src/apiSetupHelpers.ts @@ -21,9 +21,8 @@ import { ComputedOptions, MethodOptions } from './componentOptions' -import { +import ComponentObjectPropsOptions, { ComponentPropsOptions, - ComponentObjectPropsOptions, ExtractPropTypes, NormalizedProps, PropOptions diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 8c9e6a4b8fc..365d72add09 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -49,9 +49,10 @@ export type ComponentPropsOptions

= | ComponentObjectPropsOptions

| string[] -export type ComponentObjectPropsOptions

= { +type ComponentObjectPropsOptions

= { [K in keyof P]: Prop | null } +export default ComponentObjectPropsOptions export type Prop = PropOptions | PropType @@ -61,7 +62,6 @@ export interface PropOptions { type?: PropType | true | null required?: boolean default?: D | DefaultFactory | null | undefined | object - // validator?: (this: void, value: unknown) => boolean validator?(value: unknown): boolean /** * @internal diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index a5a23cb26b6..27868b49a02 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -171,6 +171,14 @@ export function h

( children?: RawChildren | RawSlots ): VNode +// vnode +export function h(type: VNode, children?: RawChildren): VNode +export function h

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

( diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 23ebe52f5f4..a56d453743d 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -262,7 +262,7 @@ export type { Prop, PropType, ComponentPropsOptions, - ComponentObjectPropsOptions, + default as ComponentObjectPropsOptions, ExtractPropTypes, ExtractPublicPropTypes, ExtractDefaultPropTypes From 1d40c768c3dd12842233527225ca3425c999edb0 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Wed, 15 Nov 2023 08:53:12 +0000 Subject: [PATCH 25/79] add vnode support --- packages/dts-test/defineComponent.test-d.tsx | 2 +- packages/dts-test/h.test-d.ts | 5 ++++- packages/runtime-core/src/h.ts | 7 +++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index 8c33adf3f11..4c1d2bd430a 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -320,7 +320,7 @@ describe('with object props', () => { props: { myProp: { type: Number, - validator: (val: unknown) => { + validator(val) { // @ts-expect-error return val !== this.otherProp }, diff --git a/packages/dts-test/h.test-d.ts b/packages/dts-test/h.test-d.ts index 0e4af50a51c..0a403a93b65 100644 --- a/packages/dts-test/h.test-d.ts +++ b/packages/dts-test/h.test-d.ts @@ -8,7 +8,8 @@ import { Suspense, Component, resolveComponent, - ConcreteComponent + ConcreteComponent, + VNode } from 'vue' import { describe, expectAssignable, expectType } from './utils' @@ -254,6 +255,8 @@ describe('h should work with multiple types', () => { h(sampleComponent, {}, []) }) +// usage in test-utils describe('should allow to assign vnode', () => { h(h('div', 'test')) + h({} as unknown as VNode | string | { render: Function } | Component) }) diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index 27868b49a02..332c9656aa6 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -180,9 +180,12 @@ export function h

( ): VNode // catch all types -export function h(type: string | Constructor, children?: RawChildren): VNode +export function h( + type: VNode | string | Constructor, + children?: RawChildren +): VNode export function h

( - type: string | Component

, + type: VNode | string | Component

, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots ): VNode From 998607ece92be03c730e1177633c4b31bd184a93 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Wed, 15 Nov 2023 11:16:49 +0000 Subject: [PATCH 26/79] few more changes --- .../runtime-core/src/apiDefineComponent.ts | 3 +- packages/runtime-core/src/componentOptions.ts | 8 +- .../src/componentPublicInstance.ts | 66 +++-- .../runtime-core/src/componentTypeHelpers.ts | 276 +++++------------- 4 files changed, 123 insertions(+), 230 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 8b8c2a20b2f..440f0e241c4 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -74,7 +74,8 @@ export type DefineComponent< Defaults, true, I, - S + S, + Options > > & Omit< diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index a9738aeb882..62f0c70218e 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -218,7 +218,7 @@ export type ComponentOptionsWithoutProps< M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - E extends EmitsOptions = EmitsOptions, + E extends EmitsOptions = {}, EE extends string = string, I extends ComponentInjectOptions = {}, II extends string = string, @@ -266,7 +266,7 @@ export type ComponentOptionsWithArrayProps< M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - E extends EmitsOptions = EmitsOptions, + E extends EmitsOptions = {}, EE extends string = string, I extends ComponentInjectOptions = {}, II extends string = string, @@ -317,7 +317,7 @@ export type ComponentOptionsWithObjectProps< M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - E extends EmitsOptions = EmitsOptions, + E extends EmitsOptions = {}, EE extends string = string, I extends ComponentInjectOptions = {}, II extends string = string, @@ -368,7 +368,7 @@ export type ComponentOptions< M extends MethodOptions = any, Mixin extends ComponentOptionsMixin = any, Extends extends ComponentOptionsMixin = any, - E extends EmitsOptions = any, + E extends EmitsOptions = {}, I extends ComponentInjectOptions = {}, S extends SlotsType = any > = ComponentOptionsBase< diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 6ef0c1b9ff2..1d846c8fba5 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -116,19 +116,48 @@ export type UnwrapMixinsType< type EnsureNonVoid = T extends void ? {} : T +/** + * + 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 = {} + */ export type ComponentPublicInstanceConstructor< T extends ComponentPublicInstance< Props, RawBindings, D, C, - M + M, + E, + PublicProps, + Defaults, + MakeDefaultsOptional, + Options, + I, + S > = ComponentPublicInstance, Props = any, RawBindings = any, D = any, C extends ComputedOptions = ComputedOptions, - M extends MethodOptions = MethodOptions + 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 @@ -150,6 +179,21 @@ export type CreateComponentPublicInstance< MakeDefaultsOptional extends boolean = false, I extends ComponentInjectOptions = {}, S extends SlotsType = {}, + Options = ComponentOptionsBase< + P, + B, + D, + C, + M, + Mixin, + Extends, + E, + string, + Defaults, + {}, + string, + S + >, PublicMixin = IntersectionMixin & IntersectionMixin, PublicP = UnwrapMixinsType & EnsureNonVoid

, PublicB = UnwrapMixinsType & EnsureNonVoid, @@ -170,21 +214,7 @@ export type CreateComponentPublicInstance< PublicProps, PublicDefaults, MakeDefaultsOptional, - ComponentOptionsBase< - P, - B, - D, - C, - M, - Mixin, - Extends, - E, - string, - Defaults, - {}, - string, - S - >, + Options, I, S > @@ -200,7 +230,7 @@ export type ComponentPublicInstance< PublicProps = P, Defaults = {}, MakeDefaultsOptional extends boolean = false, - Options = ComponentOptionsBase, + Options = any, I extends ComponentInjectOptions = {}, S extends SlotsType = {} > = { diff --git a/packages/runtime-core/src/componentTypeHelpers.ts b/packages/runtime-core/src/componentTypeHelpers.ts index bbe94633fbd..ed7f45f63a5 100644 --- a/packages/runtime-core/src/componentTypeHelpers.ts +++ b/packages/runtime-core/src/componentTypeHelpers.ts @@ -3,8 +3,13 @@ import { RawOptionsSymbol } from './apiDefineComponent' import { EmitFn, EmitsOptions, EmitsToProps } from './componentEmits' import { ExtractPropTypes } from './componentProps' import { Slot, Slots } from './componentSlots' -import { VNode } from '.' -import { IntersectionMixin, UnwrapMixinsType } from './componentPublicInstance' +import { Component, FunctionalComponent, VNode } from '.' +import { + ComponentPublicInstance, + ComponentPublicInstanceConstructor, + IntersectionMixin, + UnwrapMixinsType +} from './componentPublicInstance' export type ExtractComponentOptions = T extends { [RawOptionsSymbol]: infer Options @@ -87,6 +92,10 @@ export type ExtractComponentEmits = T extends ComponentOptionsBase< ? 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 [ @@ -123,15 +132,17 @@ export type ComponentProps< : unknown : unknown : {}) & - (ExtractComponentProp extends infer P - ? P extends Readonly> - ? [V] extends [string] - ? Readonly<{ [key in V]?: any }> - : {} - : ExtractPropTypes

- : {}) & - // props to be omitted since we don't need them here - ResolveMixinProps> + (T extends { $props: infer P } + ? P + : (ExtractComponentProp extends infer P + ? P extends Readonly> + ? [V] extends [string] + ? Readonly<{ [key in V]?: any }> + : {} + : ExtractPropTypes

+ : {}) & + // props to be omitted since we don't need them here + ResolveMixinProps>) export type ComponentSlots = ExtractComponentSlots extends infer S ? { @@ -145,213 +156,64 @@ export type ComponentEmits = ExtractComponentEmits extends infer E : EmitFn : () => void -// export type ComponentDefineOptions< -// // OriginalProps = never, -// 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 = {}, -// // test stuff -// // PropNames extends string = Props extends string ? Props : never, -// PropOptions extends ComponentObjectPropsOptions< -// Record -// > = ComponentObjectPropsOptions> -// > = -// | (Options & { -// props?: [Props] extends [string] ? Props[] : PropOptions -// // [K: string] :any -// } & (Props extends string -// ? ComponentOptionsWithArrayProps< -// Props, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// I, -// II, -// S -// > -// : [Props] extends [undefined] -// ? ComponentOptionsWithoutProps< -// {}, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// I, -// II, -// S -// > -// : [Props] extends [ComponentObjectPropsOptions] -// ? ComponentOptionsWithObjectProps< -// Props, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// I, -// II, -// S -// > -// : never)) -// | ((( -// props: Props, -// ctx: SetupContext -// ) => RenderFunction | Promise) & -// Options) - -// declare function supa< -// Props = undefined, -// 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 = {} -// >( -// options: ComponentDefineOptions< -// Props, -// RawBindings, -// D, -// C, -// M, -// Mixin, -// Extends, -// E, -// EE, -// I, -// II, -// S, -// Options -// > -// ): Options - -// const a = supa({ -// NonExistentOption: 'assa', -// setup(props) {} -// }) - -// const e = supa({}) +// from other PR https://github.com/vuejs/core/pull/5408 +export type ComponentInstance = T extends { new (): ComponentPublicInstance } + ? InstanceType + : T extends FunctionalComponent + ? ComponentPublicInstance + : T extends ComponentPublicInstanceConstructor + ? InstanceType + : T extends Component< + infer Props, + infer RawBindings, + infer D, + infer C, + infer M + > + ? // NOTE we override Props/RawBindings/D to make sure is not `unknown` + ComponentPublicInstance< + unknown extends Props ? {} : Props, + unknown extends RawBindings ? {} : RawBindings, + unknown extends D ? {} : D, + C, + M + > + : never // not a vue Component -// const b = supa({ -// props: ['a'], -// setup(props) { -// props.a -// //@ts-expect-error -// props.b -// } -// }) +// declare function getInstance(component: T): ComponentInstance +// declare function getProps(vm: T): ComponentProps +// declare function getEmits(vm: T): ExtractComponentEmits -// const c = supa({ +// const o = defineComponent({ // props: { -// a: String, -// b: { -// type: String, -// required: true -// } +// a: String // }, -// setup(props) { -// props.a -// props.b -// //@ts-expect-error -// props.c -// } +// emits: ['modelValueChange'] // }) -// const f = supa(() => () => '') -// const aa = supa({ -// // props: undefined, -// // props: undefined as never, -// setup(props) { -// return () => h('div') -// } -// }) +// // const oo = new o() +// // oo.$props.$attrs.test -// const v = supa({ +// const c = defineComponent({ // props: { -// a: String, -// aa: null, -// b: { -// type: String, -// required: true, -// validator: (b: unknown) => { -// // this. -// return true -// } -// }, -// c: { -// type: Boolean -// // validator(b: unknown) { -// // return false -// // } -// } -// // d: { -// // type: String, -// // validator(b: unknown): boolean { -// // return false -// // }, -// // required: true -// // } -// }, -// setup(props) { -// props.b, props.c +// a: String // }, -// ssss(p, c) { -// c +// // emits: ['modelValueChange'] +// emits: { +// test: (v: string) => true // } // }) -// const pp = ComponentObjectProps({ -// props: { -// a: String, -// b: { -// type: String, -// validator(b) { -// return true -// } -// } -// } -// }) - -// declare function propValidation(options: ComponentObjectPropsOptions): T +// const a = getInstance(c) +// // a.bb +// // a.aa +// // a.cc +// // a.dd -// propValidation({ -// a: String, -// b: { -// type: String, -// validator(b) { -// return true -// } -// } -// }) +// // a.$props.$attrs.tesr +// // const p = getProps(a) +// // p.$attrs.test +// // p. -// declare function ComponentObjectProps( -// options: ComponentOptionsWithObjectProps -// ): T +// const ee = getEmits(c) +// const e = getEmits(a) From 633b8528ad88615ae58c3b972ca25475d880fb1f Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Thu, 16 Nov 2023 10:10:12 +0000 Subject: [PATCH 27/79] more work --- .../dts-test/componentTypeHelpers.test-d.ts | 83 ++++++++++++++++++- .../runtime-core/src/apiDefineComponent.ts | 16 +++- .../src/componentPublicInstance.ts | 1 + .../runtime-core/src/componentTypeHelpers.ts | 46 +++++++--- packages/runtime-core/src/index.ts | 2 +- 5 files changed, 133 insertions(+), 15 deletions(-) diff --git a/packages/dts-test/componentTypeHelpers.test-d.ts b/packages/dts-test/componentTypeHelpers.test-d.ts index fb49c625ee0..d6e277b2412 100644 --- a/packages/dts-test/componentTypeHelpers.test-d.ts +++ b/packages/dts-test/componentTypeHelpers.test-d.ts @@ -4,7 +4,13 @@ import { ExtractComponentOptions, ComponentProps, defineComponent, - defineAsyncComponent + defineAsyncComponent, + ComponentOptions, + Prop, + ref, + ComponentInstance, + CreateComponentPublicInstance, + ComponentPublicInstance } from 'vue' const propsOptions = { @@ -54,6 +60,10 @@ const noPropsOptions = { } } +const fakeClassComponent = {} as { + new (): { $props: { a: string }; someMethod: (a: number) => void } +} + // const mixIn = { // props: ['a1'], // mixins: [propsOptions, arrayOptions, noPropsOptions] @@ -122,6 +132,12 @@ describe('Extract Component Options', () => { // @ts-expect-error checking if is not any expectType>({ bar: 'foo' }) }) + + describe('class component', () => { + expectType>( + fakeClassComponent + ) + }) }) describe('Component Props', () => { @@ -224,4 +240,69 @@ describe('Component Props', () => { bb: boolean }>({} as ComponentProps) }) + + describe('class component', () => { + expectType<{ a: string }>({} as ComponentProps) + }) +}) + +// Component Instance + +declare function retrieveComponentInstance( + component: T +): ComponentInstance + +expectType( + retrieveComponentInstance(defineComponent({})) +) + +expectType( + retrieveComponentInstance( + defineComponent({ + props: { + a: String + } + }) + ) +) + +const b = retrieveComponentInstance( + defineComponent({ + emits: { + test: () => true + } + }) +) + +expectType( + retrieveComponentInstance( + defineComponent({ + emits: { + test: () => true + } + }) + ) +) + +const a = defineComponent({ + props: [], + emits: { + a: (v: string) => true + } }) + +declare function test(t: T): ComponentInstance +declare function test2( + t: T +): CreateComponentPublicInstance + +const aa = test(a) + +aa.$emit +bb.$emit + +declare function ttt(t: T, t2: T): T +ttt(aa.$emit, bb.$emit) + +declare const bb: ComponentPublicInstance +const aaa = test2(aa) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 440f0e241c4..1f38b1b716d 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -37,6 +37,8 @@ type ResolveProps = Readonly< ? { [key in Props]?: any } : [Props] extends [ComponentObjectPropsOptions] ? ExtractPropTypes + : Props extends never[] + ? {} : Props) & ({} extends E ? {} : EmitsToProps) > @@ -119,7 +121,11 @@ export type ComponentDefineOptions< // > = ComponentObjectPropsOptions> > = | (Options & { - props?: [Props] extends [string] ? Array : Props + props?: [Props] extends [never] + ? string[] + : [Props] extends [string] + ? Array + : Props } & ([Props] extends [string] ? ComponentOptionsWithArrayProps< Props, @@ -484,7 +490,13 @@ export function defineComponent< Options > ): DefineComponent< - [Props] extends [string] ? Props[] : undefined extends Props ? {} : Props, + [Props] extends [string] + ? Props[] + : undefined extends Props + ? {} + : Props extends never[] + ? string[] + : Props, RawBindings, D, C, diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 1d846c8fba5..86abd1b88bf 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -218,6 +218,7 @@ export type CreateComponentPublicInstance< I, S > + // public properties exposed on the proxy, which is used as the render context // in templates (as `this` in the render option) export type ComponentPublicInstance< diff --git a/packages/runtime-core/src/componentTypeHelpers.ts b/packages/runtime-core/src/componentTypeHelpers.ts index ed7f45f63a5..c0090328283 100644 --- a/packages/runtime-core/src/componentTypeHelpers.ts +++ b/packages/runtime-core/src/componentTypeHelpers.ts @@ -1,7 +1,11 @@ import { ComponentOptionsBase } from './componentOptions' import { RawOptionsSymbol } from './apiDefineComponent' import { EmitFn, EmitsOptions, EmitsToProps } from './componentEmits' -import { ExtractPropTypes } from './componentProps' +import { + ComponentPropsOptions, + ExtractDefaultPropTypes, + ExtractPropTypes +} from './componentProps' import { Slot, Slots } from './componentSlots' import { Component, FunctionalComponent, VNode } from '.' import { @@ -37,7 +41,7 @@ export type ExtractComponentOptions = T extends { slots?: any } ? T - : never + : T export type ExtractComponentProp = T extends { props: infer P } ? P @@ -120,6 +124,12 @@ type ResolveMixin = [T] extends [ ? IntersectionMixin & IntersectionMixin : {} +export type ComponentPropsWithDefaultOptional = ExtractDefaultPropTypes< + ExtractComponentProp +> extends infer Defaults + ? Partial & Omit, keyof Defaults> + : {} + type ResolveMixinProps = UnwrapMixinsType, 'P'> export type ComponentProps< @@ -139,10 +149,12 @@ export type ComponentProps< ? [V] extends [string] ? Readonly<{ [key in V]?: any }> : {} - : ExtractPropTypes

+ : P extends ComponentPropsOptions + ? ExtractPropTypes

+ : P : {}) & // props to be omitted since we don't need them here - ResolveMixinProps>) + (T extends { props: any } ? ResolveMixinProps> : {})) export type ComponentSlots = ExtractComponentSlots extends infer S ? { @@ -158,11 +170,11 @@ export type ComponentEmits = ExtractComponentEmits extends infer E // from other PR https://github.com/vuejs/core/pull/5408 export type ComponentInstance = T extends { new (): ComponentPublicInstance } - ? InstanceType + ? InstanceType //& { a: 1 } : T extends FunctionalComponent - ? ComponentPublicInstance + ? ComponentPublicInstance //& { b: 1 } : T extends ComponentPublicInstanceConstructor - ? InstanceType + ? InstanceType //& { c: 1 } : T extends Component< infer Props, infer RawBindings, @@ -177,19 +189,31 @@ export type ComponentInstance = T extends { new (): ComponentPublicInstance } unknown extends D ? {} : D, C, M - > + > & { d: 1 } : never // not a vue Component // declare function getInstance(component: T): ComponentInstance // declare function getProps(vm: T): ComponentProps // declare function getEmits(vm: T): ExtractComponentEmits +// declare function getDefaults(vm: T): ComponentPropsWithDefaultOptional + // const o = defineComponent({ -// props: { -// a: String +// // props: { +// // a: Boolean, + +// // s: String +// // }, +// // emits: ['modelValueChange'] +// }) +// const ComponentWithEmits = defineComponent({ +// emits: { +// hi: () => true // }, -// emits: ['modelValueChange'] +// props: [], +// template: '' // }) +// const aa = getDefaults(o) // // const oo = new o() // // oo.$props.$attrs.test diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index a56d453743d..a13f87bdfd7 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -226,7 +226,7 @@ export type { ComponentCustomProps, AllowedComponentProps } from './component' -export type { DefineComponent } from './apiDefineComponent' +export type { DefineComponent, ComponentDefineOptions } from './apiDefineComponent' export type { ComponentOptions, ComponentOptionsMixin, From 96f244a0337d79db9332122162e0b4af3645a49c Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Thu, 16 Nov 2023 15:31:38 +0000 Subject: [PATCH 28/79] more improvements --- .../dts-test/componentTypeHelpers.test-d.ts | 125 +++++++++++++++--- .../runtime-core/src/apiDefineComponent.ts | 2 +- packages/runtime-core/src/componentProps.ts | 2 +- .../runtime-core/src/componentTypeHelpers.ts | 79 +++++++++-- 4 files changed, 178 insertions(+), 30 deletions(-) diff --git a/packages/dts-test/componentTypeHelpers.test-d.ts b/packages/dts-test/componentTypeHelpers.test-d.ts index d6e277b2412..0620648b64d 100644 --- a/packages/dts-test/componentTypeHelpers.test-d.ts +++ b/packages/dts-test/componentTypeHelpers.test-d.ts @@ -5,12 +5,18 @@ import { ComponentProps, defineComponent, defineAsyncComponent, - ComponentOptions, - Prop, - ref, ComponentInstance, CreateComponentPublicInstance, - ComponentPublicInstance + ComponentPublicInstance, + ComponentPropsWithDefaultOptional, + ComponentDefineOptions, + ComputedOptions, + MethodOptions, + ComponentOptionsMixin, + EmitsOptions, + ComponentInjectOptions, + SlotsType, + DefineComponent } from 'vue' const propsOptions = { @@ -273,17 +279,6 @@ const b = retrieveComponentInstance( } }) ) - -expectType( - retrieveComponentInstance( - defineComponent({ - emits: { - test: () => true - } - }) - ) -) - const a = defineComponent({ props: [], emits: { @@ -305,4 +300,102 @@ declare function ttt(t: T, t2: T): T ttt(aa.$emit, bb.$emit) declare const bb: ComponentPublicInstance -const aaa = test2(aa) +// const aaa = test2(aa) + +// declare function extraPropsOptional( +// o: T & { +// props?: PropNames[] | Props +// } +// ): ComponentPropsWithDefaultOptional + +declare function extraPropsOptional< + 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 = {} +>( + o: 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 + > +> + +// declare function antoher< +// T extends DefineComponent< +// PropsOrOptions, +// any, +// any, +// any, +// any, +// any, +// any, +// any, +// any, +// any +// >, +// PropsOrOptions extends object +// >(o: T): ComponentInstance & { LOL: T} +// const Foo = { +// props: ['obj', 'foo'] as ['obj', 'foo'], +// template: ` +//

+//
foo
+//
+// ` +// } + +// const asd = antoher(Foo) +// asd.$props.obj +// const axxx = defineComponent({ +// props: ['ax'] +// }) +// const asd = extraPropsOptional({ +// mixins: [axxx], +// props: { +// axx: String +// }, +// setup(props) { +// } +// }) + +// const aasd : keyof {} + +// asd.axx +// asd.ax +// asd.asad diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 1f38b1b716d..c42a7eb4f0d 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -32,7 +32,7 @@ export type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps -type ResolveProps = Readonly< +export type ResolveProps = Readonly< ([Props] extends [string] ? { [key in Props]?: any } : [Props] extends [ComponentObjectPropsOptions] diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 365d72add09..9ef641b4cd6 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -175,7 +175,7 @@ const enum BooleanFlags { } // extract props which defined with default from prop options -export type ExtractDefaultPropTypes = O extends object +export type ExtractDefaultPropTypes = [O] extends [object] ? // use `keyof Pick>` instead of `DefaultKeys` to support IDE features { [K in keyof Pick>]: InferPropType } : {} diff --git a/packages/runtime-core/src/componentTypeHelpers.ts b/packages/runtime-core/src/componentTypeHelpers.ts index c0090328283..1ccf1da75d4 100644 --- a/packages/runtime-core/src/componentTypeHelpers.ts +++ b/packages/runtime-core/src/componentTypeHelpers.ts @@ -1,5 +1,9 @@ import { ComponentOptionsBase } from './componentOptions' -import { RawOptionsSymbol } from './apiDefineComponent' +import { + ComponentDefineOptions, + RawOptionsSymbol, + defineComponent +} from './apiDefineComponent' import { EmitFn, EmitsOptions, EmitsToProps } from './componentEmits' import { ComponentPropsOptions, @@ -123,12 +127,22 @@ type ResolveMixin = [T] extends [ ] ? IntersectionMixin & IntersectionMixin : {} - -export type ComponentPropsWithDefaultOptional = ExtractDefaultPropTypes< - ExtractComponentProp -> 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 // not supported because is an array of non-string + : P + : T +) extends infer Props + ? ExtractDefaultPropTypes extends infer Defaults + ? Partial & Omit, keyof Defaults> + : {} + : {}) & + (T extends { props: any } + ? ResolveMixinProps> + : ResolveMixinProps) type ResolveMixinProps = UnwrapMixinsType, 'P'> @@ -154,7 +168,9 @@ export type ComponentProps< : P : {}) & // props to be omitted since we don't need them here - (T extends { props: any } ? ResolveMixinProps> : {})) + (T extends { props: any } + ? ResolveMixinProps> + : ResolveMixinProps)) export type ComponentSlots = ExtractComponentSlots extends infer S ? { @@ -170,11 +186,50 @@ export type ComponentEmits = ExtractComponentEmits extends infer E // from other PR https://github.com/vuejs/core/pull/5408 export type ComponentInstance = T extends { new (): ComponentPublicInstance } - ? InstanceType //& { a: 1 } + ? InstanceType : T extends FunctionalComponent - ? ComponentPublicInstance //& { b: 1 } + ? ComponentPublicInstance : T extends ComponentPublicInstanceConstructor - ? InstanceType //& { c: 1 } + ? InstanceType + : T extends ComponentDefineOptions< + infer Props, + infer RawBindings, + infer D, + infer C, + infer M, + infer Mixin, + infer Extends, + infer E, + infer EE, + infer I, + infer II, + infer S, + infer Options + > + ? InstanceType< + ReturnType< + typeof defineComponent< + //just need to treat the props a little bit + Options extends { props: infer P } + ? P extends Array + ? PA + : P + : Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + I, + II, + S, + Options + > + > + > : T extends Component< infer Props, infer RawBindings, @@ -189,7 +244,7 @@ export type ComponentInstance = T extends { new (): ComponentPublicInstance } unknown extends D ? {} : D, C, M - > & { d: 1 } + > : never // not a vue Component // declare function getInstance(component: T): ComponentInstance From aab3189202fda527a03e5a1a29f5ef896642b209 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:32:51 +0000 Subject: [PATCH 29/79] [autofix.ci] apply automated fixes --- packages/runtime-core/src/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index a13f87bdfd7..bcf23224035 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -226,7 +226,10 @@ export type { ComponentCustomProps, AllowedComponentProps } from './component' -export type { DefineComponent, ComponentDefineOptions } from './apiDefineComponent' +export type { + DefineComponent, + ComponentDefineOptions +} from './apiDefineComponent' export type { ComponentOptions, ComponentOptionsMixin, From 8a61db8135f7f27c3e750ea2c7f945312675b4c0 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Fri, 17 Nov 2023 11:15:41 +0000 Subject: [PATCH 30/79] some improvements --- .../dts-test/componentInstance.test-d.tsx | 313 ++++++++++++++++++ .../runtime-core/src/apiDefineComponent.ts | 5 - packages/runtime-core/src/componentEmits.ts | 5 +- .../runtime-core/src/componentTypeHelpers.ts | 4 +- 4 files changed, 319 insertions(+), 8 deletions(-) create mode 100644 packages/dts-test/componentInstance.test-d.tsx diff --git a/packages/dts-test/componentInstance.test-d.tsx b/packages/dts-test/componentInstance.test-d.tsx new file mode 100644 index 00000000000..428a3736665 --- /dev/null +++ b/packages/dts-test/componentInstance.test-d.tsx @@ -0,0 +1,313 @@ +import { + defineComponent, + FunctionalComponent, + ComponentPublicInstance, + ComponentInstance, + ref +} from 'vue' +import { expectType, describe } from './utils' + +declare function getComponentInstance(comp: T): ComponentInstance + +describe('defineComponent', () => { + const CompSetup = defineComponent({ + props: { + test: String + }, + setup() { + return { + a: 1 + } + } + }) + const compSetup = getComponentInstance(CompSetup) + + expectType(compSetup.test) + expectType(compSetup.a) + expectType(compSetup) +}) +describe('functional component', () => { + // Functional + const CompFunctional: FunctionalComponent<{ test?: string }> = {} as any + const compFunctional = getComponentInstance(CompFunctional) + + expectType(compFunctional.test) + expectType(compFunctional) + + const CompFunction: (props: { test?: string }) => any = {} as any + const compFunction = getComponentInstance(CompFunction) + + expectType(compFunction.test) + expectType(compFunction) + + const CompDefineFunction = defineComponent( + (props: { test?: string }) => () => {} + ) + const compDefineFunction = getComponentInstance(CompDefineFunction) + + expectType(compDefineFunction.test) + expectType(compDefineFunction) +}) + +describe('options component', () => { + // Options + const CompOptions = defineComponent({ + props: { + test: String + }, + data() { + return { + a: 1 + } + }, + computed: { + b() { + return 'test' + } + }, + methods: { + func(a: string) { + return true + } + } + }) + const compOptions: ComponentInstance = {} as any + expectType(compOptions.test) + expectType(compOptions.a) + expectType<(a: string) => boolean>(compOptions.func) + expectType(compOptions) +}) + +describe('object no defineComponent', () => { + // object - no defineComponent + + const CompObjectSetup = { + props: { + test: String + }, + setup() { + return { + a: 1 + } + } + } + const compObjectSetup: ComponentInstance = {} as any + expectType(compObjectSetup.test) + expectType(compObjectSetup.a) + expectType(compObjectSetup) + + const CompObjectData = { + props: { + test: String + }, + data() { + return { + a: 1 + } + } + } + const compObjectData: ComponentInstance = {} as any + expectType(compObjectData.test) + expectType(compObjectData.a) + expectType(compObjectData) + + const CompObjectNoProps = { + data() { + return { + a: 1 + } + } + } + const compObjectNoProps: ComponentInstance = + {} as any + expectType(compObjectNoProps.test) + expectType(compObjectNoProps.a) + expectType(compObjectNoProps) +}) + +describe('Generic component', () => { + const Comp = defineComponent( + // TODO: babel plugin to auto infer runtime props options from type + // similar to defineProps<{...}>() + (props: { msg: T; list: T[] }) => { + // use Composition API here like in