From 75e447e4047724b1e54b225da49dbe6eb81241f4 Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 19 Sep 2020 07:12:59 +0100 Subject: [PATCH 01/42] feat(types): string type inferrences --- .vscode/settings.json | 2 +- package.json | 2 +- packages/runtime-core/src/h.ts | 19 ++++++++++++++++++- test-dts/h.test-d.ts | 10 +++++++++- yarn.lock | 8 ++++---- 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 1dcc2819c28..d699de35afd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { // Use the project's typescript version - "typescript.tsdk": "node_modules/typescript/lib", + "typescript.tsdk": "c:\\dev\\vue-next\\node_modules\\typescript\\lib", "cSpell.enabledLanguageIds": ["markdown", "plaintext", "text", "yml"], diff --git a/package.json b/package.json index 1f097019ba2..322b17f399c 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "semver": "^7.3.2", "serve": "^11.3.0", "ts-jest": "^26.2.0", - "typescript": "^4.0.2", + "typescript": "next", "yorkie": "^2.0.0" } } diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index bf03247f2cb..d647bd326a0 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -68,6 +68,23 @@ interface Constructor

{ new (...args: any[]): { $props: P } } + +// Converts emits value to object +type ExtractEmitEvents = + T extends Readonly> + ? ({ [K in V & string as `on${capitalize K}`]: (...args: any[]) => void }) + : T extends any[] + ? ({ [K in T & string as `on${capitalize K}`]: (...args: any[]) => void }) + : {} extends T // if the emit is empty object (usually the default value for emit) should be converted to function + ? {} + : + { [K in keyof T & string as `on${capitalize K}`]: T[K] extends ((...args: infer Args) => any) + ? (...args: Args) => void + : (...args: any[]) => void + } + + + // The following is a series of overloads for providing props validation of // manually written render functions. @@ -105,7 +122,7 @@ export function h( // functional component export function h( type: FunctionalComponent, - props?: (RawProps & P) | ({} extends P ? null : never), + props?: (RawProps & P & Partial>) | ({} extends P ? null : never), children?: RawChildren | RawSlots ): VNode diff --git a/test-dts/h.test-d.ts b/test-dts/h.test-d.ts index 4376eaf979e..89ee863c0a0 100644 --- a/test-dts/h.test-d.ts +++ b/test-dts/h.test-d.ts @@ -8,7 +8,8 @@ import { Suspense, Component, expectError, - expectAssignable + expectAssignable, + FunctionalComponent } from './index' describe('h inference w/ element', () => { @@ -69,12 +70,19 @@ describe('h inference w/ functional component', () => { const Func = (_props: { foo: string; bar?: number }) => '' h(Func, { foo: 'hello' }) h(Func, { foo: 'hello', bar: 123 }) + // @ts-expect-error expectError(h(Func, { foo: 123 })) // @ts-expect-error expectError(h(Func, {})) // @ts-expect-error expectError(h(Func, { bar: 123 })) + + const Func2: FunctionalComponent<{}, ['foo', 'bar']> = () => {} + h(Func2, { onFoo() {}, onBar() {} }) + + // @ts-expect-error + h(Func2, { onFoo: 1 }) }) describe('h support w/ plain object component', () => { diff --git a/yarn.lock b/yarn.lock index 063307a72a5..a0b827a916e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7325,10 +7325,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2" - integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ== +typescript@next: + version "4.1.0-dev.20200918" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.0-dev.20200918.tgz#b00beedf2da8dbba09284085114e77bf8f329686" + integrity sha512-cEcXJvz55OH3k3cmpMYoVfqdAQ2YvgeccUmccmleUnQ8VqR8T/7GI761Qky/vGZO/VhiU3Y8xJF3oLkAkNrG1g== typescript@~3.9.5: version "3.9.7" From 55c6c2c833a6ddef4e013e278b41b76c30790cdb Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 19 Sep 2020 07:41:09 +0100 Subject: [PATCH 02/42] chore: add h defineComponent --- packages/runtime-core/src/h.ts | 8 ++--- test-dts/h.test-d.ts | 57 +++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index d647bd326a0..d4dbb71e140 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -137,11 +137,11 @@ export function h( ): VNode // exclude `defineComponent` constructors -export function h

( - type: ComponentOptions

, - props?: (RawProps & P) | ({} extends P ? null : never), +export function h( + type: ComponentOptions, + props?: (Partial> & RawProps & P ) | ({} extends P ? null : never), children?: RawChildren | RawSlots -): VNode +): E // fake constructor type returned by `defineComponent` or class component export function h(type: Constructor, children?: RawChildren): VNode diff --git a/test-dts/h.test-d.ts b/test-dts/h.test-d.ts index 89ee863c0a0..d0fa9ca525b 100644 --- a/test-dts/h.test-d.ts +++ b/test-dts/h.test-d.ts @@ -9,7 +9,8 @@ import { Component, expectError, expectAssignable, - FunctionalComponent + FunctionalComponent, + expectType } from './index' describe('h inference w/ element', () => { @@ -94,6 +95,44 @@ describe('h support w/ plain object component', () => { h(Foo, { foo: 'ok' }) h(Foo, { foo: 'ok', class: 'extra' }) // no inference in this case + + h( + { + emits: { + foo(a: number) { + return true + } + } + }, + { + // NOTE this should at least infer `s` as number + // ERROR caused by `RawProps` + onFoo(s) { + expectType(s) + } + } + ) + + h( + { + props: { + foo: String + }, + emits: { + foo(a: number) { + return true + } + } + }, + { + foo: 'ss', + + // NOTE this should at least infer `s` as number + onFoo(s) { + expectType(s) + } + } + ) }) describe('h inference w/ defineComponent', () => { @@ -117,6 +156,22 @@ describe('h inference w/ defineComponent', () => { expectError(h(Foo, { foo: 'ok' })) // @ts-expect-error should fail on wrong type expectError(h(Foo, { bar: 1, foo: 1 })) + + const FooEmit = defineComponent({ + emits: { + foo(a: number) { + return true + } + } + }) + + h(FooEmit, { + // NOTE it should infer the correct argument, + // it infers the key `onFoo` but not the argument type :thinking: + onFoo(a) { + expectType(a) + } + }) }) // describe('h inference w/ defineComponent + optional props', () => { From b99a54310b345250c8998f6956fdfcad533cd76d Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 19 Sep 2020 07:59:27 +0100 Subject: [PATCH 03/42] chore: v-model emit update:${props} --- packages/runtime-core/src/component.ts | 6 +++--- packages/runtime-core/src/componentEmits.ts | 12 ++++++++---- packages/runtime-core/src/componentOptions.ts | 2 +- packages/runtime-core/src/componentPublicInstance.ts | 2 +- test-dts/functionalComponent.test-d.tsx | 7 +++++++ 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 78abad60a8a..649a3b9d727 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -105,7 +105,7 @@ export interface ComponentInternalOptions { export interface FunctionalComponent

extends ComponentInternalOptions { // use of any here is intentional so it can be a valid JSX Element constructor - (props: P, ctx: SetupContext): any + (props: P, ctx: SetupContext): any props?: ComponentPropsOptions

emits?: E | (keyof E)[] inheritAttrs?: boolean @@ -167,10 +167,10 @@ export const enum LifecycleHooks { ERROR_CAPTURED = 'ec' } -export interface SetupContext { +export interface SetupContext { attrs: Data slots: Slots - emit: EmitFn + emit: EmitFn } /** diff --git a/packages/runtime-core/src/componentEmits.ts b/packages/runtime-core/src/componentEmits.ts index 6418f8c7d5d..a49563c24ad 100644 --- a/packages/runtime-core/src/componentEmits.ts +++ b/packages/runtime-core/src/componentEmits.ts @@ -25,11 +25,14 @@ export type ObjectEmitsOptions = Record< > export type EmitsOptions = ObjectEmitsOptions | string[] +export type EmitVModelUpdate = (event: `update:${E}`, value: T[E])=> void //{ [K in keyof T & string as `update:${K}`]: (value:T[K])=> void } + export type EmitFn< Options = ObjectEmitsOptions, - Event extends keyof Options = keyof Options -> = Options extends any[] - ? (event: Options[0], ...args: any[]) => void + P = {}, + Event extends keyof Options = keyof Options, +> = (Options extends Array + ? (event: V, ...args: any[]) => void : {} extends Options // if the emit is empty object (usually the default value for emit) should be converted to function ? (event: string, ...args: any[]) => void : UnionToIntersection< @@ -38,7 +41,8 @@ export type EmitFn< ? (event: key, ...args: Args) => void : (event: key, ...args: any[]) => void }[Event] - > + > +) & EmitVModelUpdate

export function emit( instance: ComponentInternalInstance, diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 69f1f2afd1e..f671eb0df1f 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -94,7 +94,7 @@ export interface ComponentOptionsBase< setup?: ( this: void, props: Props, - ctx: SetupContext + ctx: SetupContext ) => Promise | RawBindings | RenderFunction | void name?: string template?: string | object // can be a direct DOM node diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index e0e239a7997..20de421c22d 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -181,7 +181,7 @@ export type ComponentPublicInstance< $slots: Slots $root: ComponentPublicInstance | null $parent: ComponentPublicInstance | null - $emit: EmitFn + $emit: EmitFn $el: any $options: Options $forceUpdate: ReactiveEffect diff --git a/test-dts/functionalComponent.test-d.tsx b/test-dts/functionalComponent.test-d.tsx index c53c4287a6e..7a969f5c293 100644 --- a/test-dts/functionalComponent.test-d.tsx +++ b/test-dts/functionalComponent.test-d.tsx @@ -27,12 +27,19 @@ const Bar: FunctionalComponent< expectType(props.foo) emit('update', 123) + + emit('update:foo', 123) + // @ts-expect-error expectError(emit('nope')) // @ts-expect-error expectError(emit('update')) // @ts-expect-error expectError(emit('update', 'nope')) + // @ts-expect-error + expectError(emit('update:foo')) + // @ts-expect-error + expectError(emit('update:foo', 'nope')) } // assigning runtime options From 83e9abdd20f2b8081e02badd803f1969f643f0af Mon Sep 17 00:00:00 2001 From: pikax Date: Tue, 27 Oct 2020 09:24:08 +0000 Subject: [PATCH 04/42] types(defineComponent): Support emit when using functionalComponent --- packages/runtime-core/src/apiDefineComponent.ts | 8 ++++++-- test-dts/component.test-d.ts | 9 +++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 333d18a30f3..161019410e4 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -80,10 +80,14 @@ export type DefineComponent< // overload 1: direct setup function // (uses user defined props interface) -export function defineComponent( +export function defineComponent< + Props, + RawBindings = object, + E extends EmitsOptions = {} +>( setup: ( props: Readonly, - ctx: SetupContext + ctx: SetupContext ) => RawBindings | RenderFunction ): DefineComponent diff --git a/test-dts/component.test-d.ts b/test-dts/component.test-d.ts index 30b3b8e5f53..4afe888a242 100644 --- a/test-dts/component.test-d.ts +++ b/test-dts/component.test-d.ts @@ -410,6 +410,15 @@ describe('functional', () => { expectType(props.foo) }) + + describe('emit', () => { + const MyComponent: FunctionalComponent< + { foo: number }, + { ev: (a: string) => void } + > = (_, _2) => {} + + defineComponent(MyComponent) + }) }) declare type VueClass = { From e0a16564658ee40fcebd99a06c91ae36f300ae8a Mon Sep 17 00:00:00 2001 From: pikax Date: Mon, 30 Nov 2020 17:42:35 +0000 Subject: [PATCH 05/42] types(slots): Add typed slots --- .../runtime-core/src/apiDefineComponent.ts | 33 ++++++++++++------- packages/runtime-core/src/component.ts | 4 +-- packages/runtime-core/src/componentOptions.ts | 30 ++++++++++++++--- .../src/componentPublicInstance.ts | 19 +++++++++-- packages/runtime-core/src/componentSlots.ts | 23 +++++++++++-- test-dts/defineComponent.test-d.tsx | 25 ++++++++++++++ 6 files changed, 112 insertions(+), 22 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 333d18a30f3..b5eb963609d 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -25,6 +25,7 @@ import { CreateComponentPublicInstance, ComponentPublicInstanceConstructor } from './componentPublicInstance' +import { Slots } from './componentSlots' export type PublicProps = VNodeProps & AllowedComponentProps & @@ -40,6 +41,7 @@ export type DefineComponent< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, EE extends string = string, + S = {}, PP = PublicProps, Props = Readonly>, Defaults = ExtractDefaultPropTypes @@ -53,6 +55,7 @@ export type DefineComponent< Mixin, Extends, E, + S, PP & Props, Defaults, true @@ -69,6 +72,7 @@ export type DefineComponent< Extends, E, EE, + S, Defaults > & PP @@ -80,12 +84,12 @@ export type DefineComponent< // overload 1: direct setup function // (uses user defined props interface) -export function defineComponent( +export function defineComponent( setup: ( props: Readonly, - ctx: SetupContext + ctx: SetupContext> ) => RawBindings | RenderFunction -): DefineComponent +): DefineComponent // overload 2: object format with no props // (uses user defined props interface) @@ -99,7 +103,8 @@ export function defineComponent< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, - EE extends string = string + EE extends string = string, + S = {} >( options: ComponentOptionsWithoutProps< Props, @@ -110,9 +115,10 @@ export function defineComponent< Mixin, Extends, E, - EE + EE, + S > -): DefineComponent +): DefineComponent // overload 3: object format with array props declaration // props inferred as { [key in PropNames]?: any } @@ -126,7 +132,8 @@ export function defineComponent< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, - EE extends string = string + EE extends string = string, + S = {} >( options: ComponentOptionsWithArrayProps< PropNames, @@ -137,7 +144,8 @@ export function defineComponent< Mixin, Extends, E, - EE + EE, + S > ): DefineComponent< Readonly<{ [key in PropNames]?: any }>, @@ -148,7 +156,8 @@ export function defineComponent< Mixin, Extends, E, - EE + EE, + S > // overload 4: object format with object props declaration @@ -164,7 +173,8 @@ export function defineComponent< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, - EE extends string = string + EE extends string = string, + S = {} >( options: ComponentOptionsWithObjectProps< PropsOptions, @@ -175,7 +185,8 @@ export function defineComponent< Mixin, Extends, E, - EE + EE, + S > ): DefineComponent diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 9b1fdcef18f..31ab9e73d1f 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -167,9 +167,9 @@ export const enum LifecycleHooks { ERROR_CAPTURED = 'ec' } -export interface SetupContext { +export interface SetupContext { attrs: Data - slots: Slots + slots: S emit: EmitFn expose: (exposed: Record) => void } diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 89bd8c06053..b776840223c 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -59,6 +59,7 @@ import { import { warn } from './warning' import { VNodeChild } from './vnode' import { callWithAsyncErrorHandling } from './errorHandling' +import { Slots } from './componentSlots' /** * Interface for declaring custom options. @@ -90,6 +91,7 @@ export interface ComponentOptionsBase< Extends extends ComponentOptionsMixin, E extends EmitsOptions, EE extends string = string, + S = {}, Defaults = {} > extends LegacyOptions, @@ -98,7 +100,7 @@ export interface ComponentOptionsBase< setup?: ( this: void, props: Props, - ctx: SetupContext + ctx: SetupContext> ) => Promise | RawBindings | RenderFunction | void name?: string template?: string | object // can be a direct DOM node @@ -116,6 +118,8 @@ export interface ComponentOptionsBase< expose?: string[] serverPrefetch?(): Promise + slots?: S & ThisType + // Internal ------------------------------------------------------------------ /** @@ -178,7 +182,8 @@ export type ComponentOptionsWithoutProps< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, - EE extends string = string + EE extends string = string, + S = {} > = ComponentOptionsBase< Props, RawBindings, @@ -189,11 +194,22 @@ export type ComponentOptionsWithoutProps< Extends, E, EE, + S, {} > & { props?: undefined } & ThisType< - CreateComponentPublicInstance<{}, RawBindings, D, C, M, Mixin, Extends, E> + CreateComponentPublicInstance< + {}, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + S + > > export type ComponentOptionsWithArrayProps< @@ -206,6 +222,7 @@ export type ComponentOptionsWithArrayProps< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, EE extends string = string, + S = {}, Props = Readonly<{ [key in PropNames]?: any }> > = ComponentOptionsBase< Props, @@ -217,6 +234,7 @@ export type ComponentOptionsWithArrayProps< Extends, E, EE, + S, {} > & { props: PropNames[] @@ -229,7 +247,8 @@ export type ComponentOptionsWithArrayProps< M, Mixin, Extends, - E + E, + S > > @@ -243,6 +262,7 @@ export type ComponentOptionsWithObjectProps< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, EE extends string = string, + S = {}, Props = Readonly>, Defaults = ExtractDefaultPropTypes > = ComponentOptionsBase< @@ -255,6 +275,7 @@ export type ComponentOptionsWithObjectProps< Extends, E, EE, + S, Defaults > & { props: PropsOptions & ThisType @@ -268,6 +289,7 @@ export type ComponentOptionsWithObjectProps< Mixin, Extends, E, + S, Props, Defaults, false diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 1e62f8b16c5..3d980085d5c 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -79,6 +79,7 @@ type MixinToOptionTypes = T extends ComponentOptionsBase< infer Extends, any, any, + any, infer Defaults > ? OptionTypesType

& @@ -131,6 +132,7 @@ export type CreateComponentPublicInstance< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = {}, + S = {}, PublicProps = P, Defaults = {}, MakeDefaultsOptional extends boolean = false, @@ -151,10 +153,11 @@ export type CreateComponentPublicInstance< PublicC, PublicM, E, + S, PublicProps, PublicDefaults, MakeDefaultsOptional, - ComponentOptionsBase + ComponentOptionsBase > // public properties exposed on the proxy, which is used as the render context @@ -166,10 +169,22 @@ export type ComponentPublicInstance< C extends ComputedOptions = {}, M extends MethodOptions = {}, E extends EmitsOptions = {}, + S = {}, PublicProps = P, Defaults = {}, MakeDefaultsOptional extends boolean = false, - Options = ComponentOptionsBase + Options = ComponentOptionsBase< + any, + any, + any, + any, + any, + any, + any, + any, + any, + any + > > = { $: ComponentInternalInstance $data: D diff --git a/packages/runtime-core/src/componentSlots.ts b/packages/runtime-core/src/componentSlots.ts index 4a6a1b75375..ea7d62f055c 100644 --- a/packages/runtime-core/src/componentSlots.ts +++ b/packages/runtime-core/src/componentSlots.ts @@ -22,11 +22,28 @@ import { isHmrUpdating } from './hmr' export type Slot = (...args: any[]) => VNode[] -export type InternalSlots = { - [name: string]: Slot | undefined +export type SlotTyped = T extends null ? () => VNode[] : (arg: T) => VNode[] + +export type InternalSlots = { + [K in keyof T]?: T[K] extends () => infer R ? SlotTyped : SlotTyped } -export type Slots = Readonly +export type SlotsObject = InternalSlots +export type SlotArray = V extends PropertyKey + ? Record + : Record + +export type Slots = unknown extends T + ? Readonly>> + : T extends Array ? Readonly> : Readonly> + +// export type Slot = (...args: any[]) => VNode[] + +// export type InternalSlots = { +// [name: string]: Slot | undefined +// } + +// export type Slots = Readonly export type RawSlots = { [name: string]: unknown diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index c77feba025d..4da454eae60 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -924,6 +924,31 @@ describe('async setup', () => { vm.a = 2 }) +describe('typed slots', () => { + const xxx = defineComponent({ + slots: { + test: null as Partial, + item: Object as () => { item: { value: number }; i: number } + }, + + setup(_, { slots }) { + slots.test!() + slots.item!({ + i: 22, + item: { + value: 22 + } + }) + + // @ts-expect-error missing item prop + expectError(slots.item!({ i: 22 })) + } + }) + + // TODO add to `h` + h(xxx, {}, {}) +}) + // check if defineComponent can be exported export default { // function components From b4dc05f7295321f1c0a404f3ff2f80d5f7d62678 Mon Sep 17 00:00:00 2001 From: pikax Date: Mon, 30 Nov 2020 17:48:48 +0000 Subject: [PATCH 06/42] chore: fix tests --- packages/runtime-core/src/apiDefineComponent.ts | 8 ++++---- packages/runtime-core/src/componentOptions.ts | 8 ++++---- packages/runtime-core/src/componentPublicInstance.ts | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index b5eb963609d..f7f6d625019 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -41,7 +41,7 @@ export type DefineComponent< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, EE extends string = string, - S = {}, + S = any, PP = PublicProps, Props = Readonly>, Defaults = ExtractDefaultPropTypes @@ -104,7 +104,7 @@ export function defineComponent< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, EE extends string = string, - S = {} + S = any >( options: ComponentOptionsWithoutProps< Props, @@ -133,7 +133,7 @@ export function defineComponent< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, EE extends string = string, - S = {} + S = any >( options: ComponentOptionsWithArrayProps< PropNames, @@ -174,7 +174,7 @@ export function defineComponent< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, EE extends string = string, - S = {} + S = any >( options: ComponentOptionsWithObjectProps< PropsOptions, diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index b776840223c..477dfb485c7 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -91,7 +91,7 @@ export interface ComponentOptionsBase< Extends extends ComponentOptionsMixin, E extends EmitsOptions, EE extends string = string, - S = {}, + S = any, Defaults = {} > extends LegacyOptions, @@ -183,7 +183,7 @@ export type ComponentOptionsWithoutProps< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, EE extends string = string, - S = {} + S = any > = ComponentOptionsBase< Props, RawBindings, @@ -222,7 +222,7 @@ export type ComponentOptionsWithArrayProps< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, EE extends string = string, - S = {}, + S = any, Props = Readonly<{ [key in PropNames]?: any }> > = ComponentOptionsBase< Props, @@ -262,7 +262,7 @@ export type ComponentOptionsWithObjectProps< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, EE extends string = string, - S = {}, + S = any, Props = Readonly>, Defaults = ExtractDefaultPropTypes > = ComponentOptionsBase< diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 3d980085d5c..d4ec425813b 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -132,7 +132,7 @@ export type CreateComponentPublicInstance< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = {}, - S = {}, + S = any, PublicProps = P, Defaults = {}, MakeDefaultsOptional extends boolean = false, @@ -169,7 +169,7 @@ export type ComponentPublicInstance< C extends ComputedOptions = {}, M extends MethodOptions = {}, E extends EmitsOptions = {}, - S = {}, + S = any, PublicProps = P, Defaults = {}, MakeDefaultsOptional extends boolean = false, From 3cb7f02a1ca6e6cfd2063bc537f2c5b90f17bb76 Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 19 Dec 2020 08:22:56 +0000 Subject: [PATCH 07/42] chore: rename `capitalize` to Capitalize --- packages/runtime-core/src/h.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index d388ef83b8b..29dc631de23 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -77,13 +77,13 @@ interface Constructor

{ // Converts emits value to object type ExtractEmitEvents = T extends Readonly> - ? ({ [K in V & string as `on${capitalize K}`]: (...args: any[]) => void }) + ? ({ [K in V & string as `on${Capitalize}`]: (...args: any[]) => void }) : T extends any[] - ? ({ [K in T & string as `on${capitalize K}`]: (...args: any[]) => void }) + ? ({ [K in T & string as `on${Capitalize}`]: (...args: any[]) => void }) : {} extends T // if the emit is empty object (usually the default value for emit) should be converted to function ? {} : - { [K in keyof T & string as `on${capitalize K}`]: T[K] extends ((...args: infer Args) => any) + { [K in keyof T & string as `on${Capitalize}`]: T[K] extends ((...args: infer Args) => any) ? (...args: Args) => void : (...args: any[]) => void } From 341b350ea360ce2e32a18fbb11ded063279ad8c9 Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 19 Dec 2020 08:23:18 +0000 Subject: [PATCH 08/42] chore: rollback package and typescript dep --- .vscode/settings.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d699de35afd..1dcc2819c28 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { // Use the project's typescript version - "typescript.tsdk": "c:\\dev\\vue-next\\node_modules\\typescript\\lib", + "typescript.tsdk": "node_modules/typescript/lib", "cSpell.enabledLanguageIds": ["markdown", "plaintext", "text", "yml"], diff --git a/package.json b/package.json index 6a823d0422a..a2d7813a3c4 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "semver": "^7.3.2", "serve": "^11.3.0", "ts-jest": "^26.2.0", - "typescript": "next", + "typescript": "^4.0.2", "yorkie": "^2.0.0" } } From 8089a6a6d3ed30575bd9e999fb02f6b0f5de84da Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 19 Dec 2020 08:44:34 +0000 Subject: [PATCH 09/42] chore: fix build --- packages/runtime-core/src/h.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index 29dc631de23..d55c4abdf3f 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -157,7 +157,7 @@ export function h( type: ComponentOptions, props?: (Partial> & RawProps & P ) | ({} extends P ? null : never), children?: RawChildren | RawSlots -): E +): VNode // fake constructor type returned by `defineComponent` or class component export function h(type: Constructor, children?: RawChildren): VNode From 415460a7f35dbd19a116a0e1491b16580f988f07 Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 19 Dec 2020 09:23:15 +0000 Subject: [PATCH 10/42] chore: trying to fix tests --- packages/runtime-core/src/component.ts | 10 ++++--- packages/runtime-core/src/componentEmits.ts | 2 +- packages/runtime-core/src/componentOptions.ts | 2 +- packages/runtime-core/src/h.ts | 26 +++++++++---------- test-dts/h.test-d.ts | 5 ---- 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 745ec4bd11b..80c50a32290 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -29,6 +29,7 @@ import { Directive, validateDirectiveName } from './directives' import { applyOptions, ComponentOptions, + ComponentOptionsMixin, ComputedOptions, MethodOptions } from './componentOptions' @@ -128,10 +129,13 @@ export type ConcreteComponent< RawBindings = any, D = any, C extends ComputedOptions = ComputedOptions, - M extends MethodOptions = MethodOptions + M extends MethodOptions = MethodOptions, + Mixin extends ComponentOptionsMixin = any, + Extends extends ComponentOptionsMixin = any, + E extends EmitsOptions = any > = - | ComponentOptions - | FunctionalComponent + | ComponentOptions + | FunctionalComponent /** * A type used in public APIs where a component type is expected. diff --git a/packages/runtime-core/src/componentEmits.ts b/packages/runtime-core/src/componentEmits.ts index 3efd49e0071..af36afc277c 100644 --- a/packages/runtime-core/src/componentEmits.ts +++ b/packages/runtime-core/src/componentEmits.ts @@ -28,7 +28,7 @@ export type ObjectEmitsOptions = Record< > export type EmitsOptions = ObjectEmitsOptions | string[] -export type EmitVModelUpdate = (event: `update:${E}`, value: T[E])=> void //{ [K in keyof T & string as `update:${K}`]: (value:T[K])=> void } +export type EmitVModelUpdate = (event: `update:${E}`, value: T[E])=> void export type EmitFn< Options = ObjectEmitsOptions, diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 84cd67c53ee..8d1bf51df43 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -298,7 +298,7 @@ export type ComponentOptions< M extends MethodOptions = any, Mixin extends ComponentOptionsMixin = any, Extends extends ComponentOptionsMixin = any, - E extends EmitsOptions = any + E extends EmitsOptions = {} > = ComponentOptionsBase & ThisType< CreateComponentPublicInstance< diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index d55c4abdf3f..5bd42acb244 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -16,7 +16,7 @@ import { ComponentOptions, ConcreteComponent } from './component' -import { EmitsOptions } from './componentEmits' +import { EmitFn, EmitsOptions } from './componentEmits' import { DefineComponent } from './apiDefineComponent' // `h` is a more user-friendly version of `createVNode` that allows omitting the @@ -66,11 +66,11 @@ type RawChildren = | (() => any) // fake constructor type returned from `defineComponent` -interface Constructor

{ +interface Constructor

{ __isFragment?: never __isTeleport?: never __isSuspense?: never - new (...args: any[]): { $props: P } + new (...args: any[]): { $props: P, $emit?: EmitFn } } @@ -139,9 +139,9 @@ export function h

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

( - type: ConcreteComponent

| string, - props?: (RawProps & P) | ({} extends P ? null : never), +export function h( + type: ConcreteComponent | string, + props?: (RawProps & P & ExtractEmitEvents) | ({} extends P ? null : never), children?: RawChildren ): VNode @@ -161,17 +161,17 @@ export function h( // fake constructor type returned by `defineComponent` or class component export function h(type: Constructor, children?: RawChildren): VNode -export function h

( - type: Constructor

, - props?: (RawProps & P) | ({} extends P ? null : never), +export function h( + type: Constructor, + props?: (Partial> & RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots -): VNode +): ExtractEmitEvents // fake constructor type returned by `defineComponent` export function h(type: DefineComponent, children?: RawChildren): VNode -export function h

( - type: DefineComponent

, - props?: (RawProps & P) | ({} extends P ? null : never), +export function h( + type: DefineComponent, + props?: (Partial> & RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots ): VNode diff --git a/test-dts/h.test-d.ts b/test-dts/h.test-d.ts index e6b4487a169..036aa0d3001 100644 --- a/test-dts/h.test-d.ts +++ b/test-dts/h.test-d.ts @@ -106,8 +106,6 @@ describe('h support w/ plain object component', () => { } }, { - // NOTE this should at least infer `s` as number - // ERROR caused by `RawProps` onFoo(s) { expectType(s) } @@ -128,7 +126,6 @@ describe('h support w/ plain object component', () => { { foo: 'ss', - // NOTE this should at least infer `s` as number onFoo(s) { expectType(s) } @@ -167,8 +164,6 @@ describe('h inference w/ defineComponent', () => { }) h(FooEmit, { - // NOTE it should infer the correct argument, - // it infers the key `onFoo` but not the argument type :thinking: onFoo(a) { expectType(a) } From f24b16123db80bac3fb8b46df8f0c17a4f642567 Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 19 Dec 2020 11:34:08 +0000 Subject: [PATCH 11/42] chore: defineComponent working as expected with `h` --- .../runtime-core/src/apiDefineComponent.ts | 13 +- packages/runtime-core/src/componentProps.ts | 2 +- packages/runtime-core/src/h.ts | 172 ++++++++++-------- test-dts/h.test-d.ts | 32 ++++ 4 files changed, 134 insertions(+), 85 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 333d18a30f3..9d98e70c3cd 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -58,8 +58,7 @@ export type DefineComponent< true > & Props -> & - ComponentOptionsBase< +> & { __isDefineComponent: true } & ComponentOptionsBase< Props, RawBindings, D, @@ -164,7 +163,9 @@ export function defineComponent< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, - EE extends string = string + EE extends string = string, + Props = Readonly>, + Defaults = ExtractDefaultPropTypes >( options: ComponentOptionsWithObjectProps< PropsOptions, @@ -175,9 +176,11 @@ export function defineComponent< Mixin, Extends, E, - EE + EE, + Props, + Defaults > -): DefineComponent +): DefineComponent, RawBindings, D, C, M, Mixin, Extends, E, EE, unknown, Props, Defaults> // implementation, close to no-op export function defineComponent(options: unknown) { diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 47b06459505..e5616044fe3 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -89,7 +89,7 @@ type DefaultKeys = { : never }[keyof T] -type InferPropType = T extends null +export type InferPropType = T extends null ? any // null & true would fail to infer : T extends { type: null | true } ? any // As TS issue https://github.com/Microsoft/TypeScript/issues/14829 // somehow `ObjectConstructor` when inferred from { (): T } becomes `any` // `BooleanConstructor` when inferred from PropConstructor(with PropMethod) becomes `Boolean` diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index 5bd42acb244..8b5aebb9bdc 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -18,6 +18,7 @@ import { } from './component' import { EmitFn, EmitsOptions } from './componentEmits' import { DefineComponent } from './apiDefineComponent' +import { ExtractDefaultPropTypes, ExtractPropTypes, InferPropType } from './componentProps' // `h` is a more user-friendly version of `createVNode` that allows omitting the // props when possible. It is intended for manually written render functions. @@ -70,7 +71,8 @@ interface Constructor

{ __isFragment?: never __isTeleport?: never __isSuspense?: never - new (...args: any[]): { $props: P, $emit?: EmitFn } + __isDefineComponent?: never + new (...args: any[]): { $props: P } } @@ -87,93 +89,105 @@ type ExtractEmitEvents = ? (...args: Args) => void : (...args: any[]) => void } - +type ExtractEmitPropUpdate

= + (P extends Readonly> + ? ({ [K in V & string as `onUpdate:${K}`]?: (value: any) => void }) + : P extends any[] + ? ({ [K in P & string as `onUpdate:${K}`]?: (value: any) => void }) + : { [K in keyof P & string as `onUpdate:${K}`]?: (value: P[K]) => void } + ) + +type RenderProps = +(Partial> & RawProps & P & ExtractEmitPropUpdate

) | ({} extends P ? Partial> | null : never); + // The following is a series of overloads for providing props validation of // manually written render functions. -// element -export function h(type: string, children?: RawChildren): VNode -export function h( - type: string, - props?: RawProps | null, - children?: RawChildren | RawSlots -): VNode - -// fragment -export function h(type: typeof Fragment, children?: VNodeArrayChildren): VNode -export function h( - type: typeof Fragment, - props?: RawProps | null, - children?: VNodeArrayChildren -): VNode - -// teleport (target prop is required) -export function h( - type: typeof Teleport, - props: RawProps & TeleportProps, - children: RawChildren -): VNode - -// suspense -export function h(type: typeof Suspense, children?: RawChildren): VNode -export function h( - type: typeof Suspense, - props?: (RawProps & SuspenseProps) | null, - children?: RawChildren | RawSlots -): VNode - -// functional component -export function h( - type: FunctionalComponent, - props?: (RawProps & P & Partial>) | ({} extends P ? null : never), - 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, - children?: RawChildren -): VNode -export function h( - type: ConcreteComponent | string, - props?: (RawProps & P & ExtractEmitEvents) | ({} extends P ? null : never), - children?: RawChildren -): VNode - -// component without props -export function h( - type: Component, - props: null, - children?: RawChildren | RawSlots -): VNode +// // element +// export function h(type: string, children?: RawChildren): VNode +// export function h( +// type: string, +// props?: RawProps | null, +// children?: RawChildren | RawSlots +// ): VNode + +// // fragment +// export function h(type: typeof Fragment, children?: VNodeArrayChildren): VNode +// export function h( +// type: typeof Fragment, +// props?: RawProps | null, +// children?: VNodeArrayChildren +// ): VNode + +// // teleport (target prop is required) +// export function h( +// type: typeof Teleport, +// props: RawProps & TeleportProps, +// children: RawChildren +// ): VNode + +// // suspense +// export function h(type: typeof Suspense, children?: RawChildren): VNode +// export function h( +// type: typeof Suspense, +// props?: (RawProps & SuspenseProps) | null, +// children?: RawChildren | RawSlots +// ): VNode + +// // functional component +// export function h( +// type: FunctionalComponent, +// props?: (RawProps & P & Partial>) | ({} extends P ? null : never), +// 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, +// children?: RawChildren +// ): VNode +// export function h( +// type: ConcreteComponent | string, +// props?: (RawProps & P & ExtractEmitEvents) | ({} extends P ? null : never), +// children?: RawChildren +// ): VNode + +// // component without props +// export function h( +// type: Component, +// props: null, +// children?: RawChildren | RawSlots +// ): VNode + +// // exclude `defineComponent` constructors +// export function h( +// type: ComponentOptions, +// props?: (Partial> & RawProps & P ) | ({} extends P ? null : never), +// children?: RawChildren | RawSlots +// ): VNode + +// // fake constructor type returned by `defineComponent` or class component +// export function h(type: Constructor, children?: RawChildren): VNode +// export function h( +// type: Constructor, +// props?: (Partial> & RawProps & P) | ({} extends P ? null : never), +// children?: RawChildren | RawSlots +// ): ExtractEmitEvents -// exclude `defineComponent` constructors -export function h( - type: ComponentOptions, - props?: (Partial> & RawProps & P ) | ({} extends P ? null : never), - children?: RawChildren | RawSlots -): VNode +// fake constructor type returned by `defineComponent` -// fake constructor type returned by `defineComponent` or class component -export function h(type: Constructor, children?: RawChildren): VNode -export function h( - type: Constructor, - props?: (Partial> & RawProps & P) | ({} extends P ? null : never), +export function h( + type: DefineComponent, + props?: RenderProps & Omit, E>, children?: RawChildren | RawSlots -): ExtractEmitEvents - -// fake constructor type returned by `defineComponent` +): P +export function h(type: DefineComponent): VNode export function h(type: DefineComponent, children?: RawChildren): VNode -export function h( - type: DefineComponent, - props?: (Partial> & RawProps & P) | ({} extends P ? null : never), - children?: RawChildren | RawSlots -): VNode // Actual implementation export function h(type: any, propsOrChildren?: any, children?: any): VNode { diff --git a/test-dts/h.test-d.ts b/test-dts/h.test-d.ts index 036aa0d3001..fd79ebe40dc 100644 --- a/test-dts/h.test-d.ts +++ b/test-dts/h.test-d.ts @@ -148,6 +148,18 @@ describe('h inference w/ defineComponent', () => { h(Foo, { bar: 1, foo: 'ok' }) // should allow extraneous props (attrs fallthrough) h(Foo, { bar: 1, foo: 'ok', class: 'extra' }) + + // should support model + h(Foo, { + bar: 1, + 'onUpdate:bar'(v) { + expectType(v) + }, + 'onUpdate:foo'(v) { + expectType(v) + } + }) + // @ts-expect-error should fail on missing required prop expectError(h(Foo, {})) // @ts-expect-error @@ -168,6 +180,26 @@ describe('h inference w/ defineComponent', () => { expectType(a) } }) + + const BarPropEmit = defineComponent({ + props: { + bar: Number + }, + emits: { + bar(a: number) { + return true + } + } + }) + + h(BarPropEmit, { + onBar(a) { + expectType(a) + }, + 'onUpdate:bar'(a) { + expectType(a) + } + }) }) // describe('h inference w/ defineComponent + optional props', () => { From 8e071039c8565eb5888d42a3cea203ec1a5e544b Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 19 Dec 2020 12:38:55 +0000 Subject: [PATCH 12/42] chore: kinda working but not really --- packages/runtime-core/src/h.ts | 150 +++++++++++++++++---------------- test-dts/h.test-d.ts | 49 ++++++----- 2 files changed, 104 insertions(+), 95 deletions(-) diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index 8b5aebb9bdc..f132e9504e0 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -13,12 +13,10 @@ import { RawSlots } from './componentSlots' import { FunctionalComponent, Component, - ComponentOptions, ConcreteComponent } from './component' -import { EmitFn, EmitsOptions } from './componentEmits' +import { EmitsOptions } from './componentEmits' import { DefineComponent } from './apiDefineComponent' -import { ExtractDefaultPropTypes, ExtractPropTypes, InferPropType } from './componentProps' // `h` is a more user-friendly version of `createVNode` that allows omitting the // props when possible. It is intended for manually written render functions. @@ -90,13 +88,14 @@ type ExtractEmitEvents = : (...args: any[]) => void } - -type ExtractEmitPropUpdate

= +type ExtractEmitPropUpdate

= (P extends Readonly> ? ({ [K in V & string as `onUpdate:${K}`]?: (value: any) => void }) : P extends any[] ? ({ [K in P & string as `onUpdate:${K}`]?: (value: any) => void }) - : { [K in keyof P & string as `onUpdate:${K}`]?: (value: P[K]) => void } + : + // we need to omit if it infers emit as props + { [K in keyof Omit}`> & string as `onUpdate:${K}`]?: (value: P[K]) => void } ) type RenderProps = @@ -105,64 +104,70 @@ type RenderProps = // The following is a series of overloads for providing props validation of // manually written render functions. -// // element -// export function h(type: string, children?: RawChildren): VNode -// export function h( -// type: string, -// props?: RawProps | null, -// children?: RawChildren | RawSlots -// ): VNode - -// // fragment -// export function h(type: typeof Fragment, children?: VNodeArrayChildren): VNode -// export function h( -// type: typeof Fragment, -// props?: RawProps | null, -// children?: VNodeArrayChildren -// ): VNode - -// // teleport (target prop is required) -// export function h( -// type: typeof Teleport, -// props: RawProps & TeleportProps, -// children: RawChildren -// ): VNode - -// // suspense -// export function h(type: typeof Suspense, children?: RawChildren): VNode -// export function h( -// type: typeof Suspense, -// props?: (RawProps & SuspenseProps) | null, -// children?: RawChildren | RawSlots -// ): VNode - -// // functional component -// export function h( -// type: FunctionalComponent, -// props?: (RawProps & P & Partial>) | ({} extends P ? null : never), -// 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, -// children?: RawChildren -// ): VNode -// export function h( -// type: ConcreteComponent | string, -// props?: (RawProps & P & ExtractEmitEvents) | ({} extends P ? null : never), -// children?: RawChildren -// ): VNode - -// // component without props -// export function h( -// type: Component, -// props: null, -// children?: RawChildren | RawSlots -// ): VNode +// functional component +// NOTE: is set on top to allow infer the props when doing +/// const Func = (_props: { foo: string; bar?: number }) => '' +/// h(Func, {}) +// otherwise it will default to `h(type: string)` +export function h( + type: FunctionalComponent, + props?: RenderProps, + children?: RawChildren | RawSlots +): VNode +export function h(type: FunctionalComponent): VNode + +// element +export function h(type: string, children?: RawChildren): VNode +export function h( + type: string, + props?: RawProps | null, + children?: RawChildren | RawSlots +): VNode + +// fragment +export function h(type: typeof Fragment, children?: VNodeArrayChildren): VNode +export function h( + type: typeof Fragment, + props?: RawProps | null, + children?: VNodeArrayChildren +): VNode + +// teleport (target prop is required) +export function h( + type: typeof Teleport, + props: RawProps & TeleportProps, + children: RawChildren +): VNode + +// suspense +export function h(type: typeof Suspense, children?: RawChildren): VNode +export function h( + type: typeof Suspense, + props?: (RawProps & SuspenseProps) | null, + 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, + props?: RenderProps, + children?: RawChildren +): VNode + +export function h

( + type: ConcreteComponent | string, + children?: RawChildren +): VNode + +// component without props +export function h( + type: Component, + props: null, + children?: RawChildren | RawSlots +): VNode // // exclude `defineComponent` constructors // export function h( @@ -171,17 +176,16 @@ type RenderProps = // children?: RawChildren | RawSlots // ): VNode -// // fake constructor type returned by `defineComponent` or class component -// export function h(type: Constructor, children?: RawChildren): VNode -// export function h( -// type: Constructor, -// props?: (Partial> & RawProps & P) | ({} extends P ? null : never), -// children?: RawChildren | RawSlots -// ): ExtractEmitEvents +// fake constructor type returned by `defineComponent` or class component +export function h( + type: Constructor, + props?: null,//RenderProps, + children?: RawChildren | RawSlots +): ExtractEmitEvents +export function h(type: Constructor, children?: RawChildren): VNode // fake constructor type returned by `defineComponent` - -export function h( +export function h( type: DefineComponent, props?: RenderProps & Omit, E>, children?: RawChildren | RawSlots diff --git a/test-dts/h.test-d.ts b/test-dts/h.test-d.ts index fd79ebe40dc..fc3db47b7b2 100644 --- a/test-dts/h.test-d.ts +++ b/test-dts/h.test-d.ts @@ -73,6 +73,16 @@ describe('h inference w/ functional component', () => { h(Func, { foo: 'hello' }) h(Func, { foo: 'hello', bar: 123 }) + h(Func, { + foo: '', + 'onUpdate:bar'(v) { + expectType(v) + }, + 'onUpdate:foo'(v) { + expectType(v) + } + }) + // @ts-expect-error expectError(h(Func, { foo: 123 })) // @ts-expect-error @@ -93,30 +103,24 @@ describe('h support w/ plain object component', () => { foo: String } } - h(Foo, { foo: 'ok' }) - h(Foo, { foo: 'ok', class: 'extra' }) - // no inference in this case - - h( - { - emits: { - foo(a: number) { - return true - } - } - }, - { - onFoo(s) { - expectType(s) - } + h(Foo, { + foo: 'ok', + 'onUpdate:foo'(v) { + expectType(v) } - ) + }) + h(Foo, { + foo: 'ok', + class: 'extra', + 'onUpdate:foo'(v) { + expectType(v) + } + }) + + // no inference in this case h( { - props: { - foo: String - }, emits: { foo(a: number) { return true @@ -124,8 +128,6 @@ describe('h support w/ plain object component', () => { } }, { - foo: 'ss', - onFoo(s) { expectType(s) } @@ -168,6 +170,9 @@ describe('h inference w/ defineComponent', () => { expectError(h(Foo, { bar: 1, foo: 1 })) const FooEmit = defineComponent({ + props: { + foo: String + }, emits: { foo(a: number) { return true From 47de0992414f32ebc7115a35268b09878017db6d Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 19 Dec 2020 13:05:29 +0000 Subject: [PATCH 13/42] chore: ... --- .../runtime-core/src/apiDefineComponent.ts | 20 +++++++++++++++++-- packages/runtime-core/src/h.ts | 19 +++++++++--------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 9d98e70c3cd..ac04df3bd85 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -58,7 +58,10 @@ export type DefineComponent< true > & Props -> & { __isDefineComponent: true } & ComponentOptionsBase< +> & /** + * just typescript + */ +{ __isDefineComponent?: true } & ComponentOptionsBase< Props, RawBindings, D, @@ -180,7 +183,20 @@ export function defineComponent< Props, Defaults > -): DefineComponent, RawBindings, D, C, M, Mixin, Extends, E, EE, unknown, Props, Defaults> +): DefineComponent< + ExtractPropTypes, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + PublicProps, + Props, + Defaults +> // implementation, close to no-op export function defineComponent(options: unknown) { diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index f132e9504e0..a168ee6fb25 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -65,7 +65,7 @@ type RawChildren = | (() => any) // fake constructor type returned from `defineComponent` -interface Constructor

{ +interface Constructor

{ __isFragment?: never __isTeleport?: never __isSuspense?: never @@ -176,14 +176,6 @@ export function h( // children?: RawChildren | RawSlots // ): VNode -// fake constructor type returned by `defineComponent` or class component -export function h( - type: Constructor, - props?: null,//RenderProps, - children?: RawChildren | RawSlots -): ExtractEmitEvents -export function h(type: Constructor, children?: RawChildren): VNode - // fake constructor type returned by `defineComponent` export function h( type: DefineComponent, @@ -193,6 +185,15 @@ export function h( + type: Constructor

, + props?: RenderProps, + children?: RawChildren | RawSlots +): ExtractEmitEvents +export function h(type: Constructor, children?: RawChildren): VNode + + // Actual implementation export function h(type: any, propsOrChildren?: any, children?: any): VNode { const l = arguments.length From 748550ca10c33de1349d157311e8139039806f8f Mon Sep 17 00:00:00 2001 From: pikax Date: Tue, 26 Jan 2021 08:27:59 +0000 Subject: [PATCH 14/42] chore: fix test --- packages/runtime-core/src/h.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index a168ee6fb25..ee3c6b041ce 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -13,7 +13,8 @@ import { RawSlots } from './componentSlots' import { FunctionalComponent, Component, - ConcreteComponent + ConcreteComponent, + ComponentOptions } from './component' import { EmitsOptions } from './componentEmits' import { DefineComponent } from './apiDefineComponent' @@ -169,12 +170,12 @@ export function h( children?: RawChildren | RawSlots ): VNode -// // exclude `defineComponent` constructors -// export function h( -// type: ComponentOptions, -// props?: (Partial> & RawProps & P ) | ({} extends P ? null : never), -// children?: RawChildren | RawSlots -// ): VNode +// exclude `defineComponent` constructors +export function h( + type: ComponentOptions, + props?: (Partial> & RawProps & P ) | ({} extends P ? null : never), + children?: RawChildren | RawSlots +): VNode // fake constructor type returned by `defineComponent` export function h( From e2cac0776920657a6171a58c56cdb5913842078d Mon Sep 17 00:00:00 2001 From: pikax Date: Tue, 9 Mar 2021 11:26:12 +0000 Subject: [PATCH 15/42] types(defineComponent): support for expose component types --- .../runtime-core/src/apiDefineComponent.ts | 75 ++++++++++++++++--- packages/runtime-core/src/componentOptions.ts | 54 +++++++++++-- .../src/componentPublicInstance.ts | 25 ++++++- test-dts/defineComponent.test-d.tsx | 17 +++++ 4 files changed, 151 insertions(+), 20 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 333d18a30f3..01aab7bdc1f 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -11,7 +11,8 @@ import { import { SetupContext, AllowedComponentProps, - ComponentCustomProps + ComponentCustomProps, + Component } from './component' import { ExtractPropTypes, @@ -25,6 +26,7 @@ import { CreateComponentPublicInstance, ComponentPublicInstanceConstructor } from './componentPublicInstance' +import { Directive } from './directives' export type PublicProps = VNodeProps & AllowedComponentProps & @@ -40,6 +42,9 @@ export type DefineComponent< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, EE extends string = string, + LC extends Record = {}, + Directives extends Record = {}, + Exposed extends string = string, PP = PublicProps, Props = Readonly>, Defaults = ExtractDefaultPropTypes @@ -69,6 +74,9 @@ export type DefineComponent< Extends, E, EE, + LC, + Directives, + Exposed, Defaults > & PP @@ -99,7 +107,10 @@ export function defineComponent< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, - EE extends string = string + EE extends string = string, + LC extends Record = {}, + Directives extends Record = {}, + Exposed extends string = string >( options: ComponentOptionsWithoutProps< Props, @@ -110,9 +121,25 @@ export function defineComponent< Mixin, Extends, E, - EE + EE, + LC, + Directives, + Exposed > -): DefineComponent +): DefineComponent< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + LC, + Directives, + Exposed +> // overload 3: object format with array props declaration // props inferred as { [key in PropNames]?: any } @@ -126,7 +153,10 @@ export function defineComponent< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, - EE extends string = string + EE extends string = string, + LC extends Record = {}, + Directives extends Record = {}, + Exposed extends string = string >( options: ComponentOptionsWithArrayProps< PropNames, @@ -137,7 +167,10 @@ export function defineComponent< Mixin, Extends, E, - EE + EE, + LC, + Directives, + Exposed > ): DefineComponent< Readonly<{ [key in PropNames]?: any }>, @@ -148,7 +181,10 @@ export function defineComponent< Mixin, Extends, E, - EE + EE, + LC, + Directives, + Exposed > // overload 4: object format with object props declaration @@ -164,7 +200,10 @@ export function defineComponent< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = Record, - EE extends string = string + EE extends string = string, + LC extends Record = {}, + Directives extends Record = {}, + Exposed extends string = string >( options: ComponentOptionsWithObjectProps< PropsOptions, @@ -175,9 +214,25 @@ export function defineComponent< Mixin, Extends, E, - EE + EE, + LC, + Directives, + Exposed > -): DefineComponent +): DefineComponent< + PropsOptions, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + LC, + Directives, + Exposed +> // implementation, close to no-op export function defineComponent(options: unknown) { diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 70948d41cf9..00ef198137c 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -104,6 +104,9 @@ export interface ComponentOptionsBase< Extends extends ComponentOptionsMixin, E extends EmitsOptions, EE extends string = string, + LC extends Record = {}, + Directives extends Record = {}, + Exposed extends string = string, Defaults = {} > extends LegacyOptions, @@ -124,12 +127,12 @@ export interface ComponentOptionsBase< // Luckily `render()` doesn't need any arguments nor does it care about return // type. render?: Function - components?: Record - directives?: Record + components?: LC + directives?: Directives inheritAttrs?: boolean emits?: (E | EE[]) & ThisType // TODO infer public instance type based on exposed keys - expose?: string[] + expose?: Exposed[] serverPrefetch?(): Promise // Internal ------------------------------------------------------------------ @@ -194,7 +197,10 @@ export type ComponentOptionsWithoutProps< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, - EE extends string = string + EE extends string = string, + LC extends Record = {}, + Directives extends Record = {}, + Exposed extends string = string > = ComponentOptionsBase< Props, RawBindings, @@ -205,6 +211,9 @@ export type ComponentOptionsWithoutProps< Extends, E, EE, + LC, + Directives, + Exposed, {} > & { props?: undefined @@ -222,6 +231,9 @@ export type ComponentOptionsWithArrayProps< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, EE extends string = string, + LC extends Record = {}, + Directives extends Record = {}, + Exposed extends string = string, Props = Readonly<{ [key in PropNames]?: any }> > = ComponentOptionsBase< Props, @@ -233,6 +245,9 @@ export type ComponentOptionsWithArrayProps< Extends, E, EE, + LC, + Directives, + Exposed, {} > & { props: PropNames[] @@ -245,7 +260,13 @@ export type ComponentOptionsWithArrayProps< M, Mixin, Extends, - E + E, + Props, + {}, + false, + LC, + Directives, + Exposed > > @@ -259,6 +280,9 @@ export type ComponentOptionsWithObjectProps< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, EE extends string = string, + LC extends Record = {}, + Directives extends Record = {}, + Exposed extends string = string, Props = Readonly>, Defaults = ExtractDefaultPropTypes > = ComponentOptionsBase< @@ -271,6 +295,9 @@ export type ComponentOptionsWithObjectProps< Extends, E, EE, + LC, + Directives, + Exposed, Defaults > & { props: PropsOptions & ThisType @@ -286,7 +313,10 @@ export type ComponentOptionsWithObjectProps< E, Props, Defaults, - false + false, + LC, + Directives, + Exposed > > @@ -298,7 +328,10 @@ export type ComponentOptions< M extends MethodOptions = any, Mixin extends ComponentOptionsMixin = any, Extends extends ComponentOptionsMixin = any, - E extends EmitsOptions = any + E extends EmitsOptions = any, + LC extends Record = {}, + Directives extends Record = {}, + Exposed extends string = string > = ComponentOptionsBase & ThisType< CreateComponentPublicInstance< @@ -310,7 +343,12 @@ export type ComponentOptions< Mixin, Extends, E, - Readonly + Readonly, + {}, + false, + LC, + Directives, + Exposed > > diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index bbdb0336092..9c63ab8d9a2 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -1,4 +1,5 @@ import { + Component, ComponentInternalInstance, Data, isStatefulComponent @@ -39,6 +40,7 @@ import { markAttrsAccessed } from './componentRenderUtils' import { currentRenderingInstance } from './componentRenderContext' import { warn } from './warning' import { UnionToIntersection } from './helpers/typeUtils' +import { Directive } from './directives' /** * Custom properties added to component instances in any way and can be accessed through `this` @@ -136,6 +138,9 @@ export type CreateComponentPublicInstance< PublicProps = P, Defaults = {}, MakeDefaultsOptional extends boolean = false, + LC extends Record = {}, + Directives extends Record = {}, + Exposed extends string = string, PublicMixin = IntersectionMixin & IntersectionMixin, PublicP = UnwrapMixinsType & EnsureNonVoid

, PublicB = UnwrapMixinsType & EnsureNonVoid, @@ -156,7 +161,22 @@ export type CreateComponentPublicInstance< PublicProps, PublicDefaults, MakeDefaultsOptional, - ComponentOptionsBase + ComponentOptionsBase< + P, + B, + D, + C, + M, + Mixin, + Extends, + E, + string, + LC, + Directives, + Exposed, + Defaults + >, + Exposed > // public properties exposed on the proxy, which is used as the render context @@ -171,7 +191,8 @@ export type ComponentPublicInstance< PublicProps = P, Defaults = {}, MakeDefaultsOptional extends boolean = false, - Options = ComponentOptionsBase + Options = ComponentOptionsBase, + Exposed extends string = string > = { $: ComponentInternalInstance $data: D diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index 949654b1b9e..fa32b4dc5c4 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -963,6 +963,23 @@ describe('async setup', () => { vm.a = 2 }) +// #3367 expose components types +describe('expose component types', () => { + const child = defineComponent({ + props: { + a: String + } + }) + + const parent = defineComponent({ + components: { + child + } + }) + + expect(parent.components!.child) +}) + // check if defineComponent can be exported export default { // function components From 3ccdc0bdd3f7825a70c8675d17402b74c1ac95f5 Mon Sep 17 00:00:00 2001 From: pikax Date: Tue, 9 Mar 2021 11:48:34 +0000 Subject: [PATCH 16/42] chore: add directive typing test --- packages/runtime-core/src/component.ts | 5 +++++ packages/runtime-core/src/componentOptions.ts | 17 +++++++++++++++- test-dts/defineComponent.test-d.tsx | 20 ++++++++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index bfb7736b410..a8b34e1da00 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -62,6 +62,11 @@ export type Data = Record */ export interface ComponentCustomProps {} +/** + * For globally defined Directives + */ +export interface ComponentCustomDirectives extends Record {} + /** * Default allowed non-declared props on component in TSX */ diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 00ef198137c..071df938a77 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -218,7 +218,22 @@ export type ComponentOptionsWithoutProps< > & { props?: undefined } & ThisType< - CreateComponentPublicInstance<{}, RawBindings, D, C, M, Mixin, Extends, E> + CreateComponentPublicInstance< + {}, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + Props, + {}, + false, + LC, + Directives, + Exposed + > > export type ComponentOptionsWithArrayProps< diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index fa32b4dc5c4..13b98edf74b 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -11,7 +11,8 @@ import { ComponentPublicInstance, ComponentOptions, SetupContext, - h + h, + Directive } from './index' describe('with object props', () => { @@ -980,6 +981,23 @@ describe('expose component types', () => { expect(parent.components!.child) }) +describe('directive typing', () => { + const customDirective: Directive = { + created(el) {} + } + + const comp = defineComponent({ + props: { + a: String + }, + directives: { + customDirective + } + }) + + expect(comp.directives!.customDirective) +}) + // check if defineComponent can be exported export default { // function components From e140b07eb17e58e50f73af23ac272835896190ed Mon Sep 17 00:00:00 2001 From: pikax Date: Tue, 9 Mar 2021 12:11:54 +0000 Subject: [PATCH 17/42] chore: exposed type suppor --- .../runtime-core/src/apiDefineComponent.ts | 7 +++++- packages/runtime-core/src/componentOptions.ts | 3 +-- .../src/componentPublicInstance.ts | 22 +++++++++++------ test-dts/defineComponent.test-d.tsx | 24 +++++++++++++++++++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 01aab7bdc1f..92f1a750a23 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -32,6 +32,8 @@ export type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps +// TODO add Com + export type DefineComponent< PropsOrPropOptions = {}, RawBindings = {}, @@ -60,7 +62,10 @@ export type DefineComponent< E, PP & Props, Defaults, - true + true, + LC, + Directives, + Exposed > & Props > & diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 071df938a77..f93cf9daa4c 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -330,8 +330,7 @@ export type ComponentOptionsWithObjectProps< Defaults, false, LC, - Directives, - Exposed + Directives > > diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 9c63ab8d9a2..e77832a7bb1 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -179,6 +179,11 @@ export type CreateComponentPublicInstance< Exposed > +export type ExposedKeys< + T, + Exposed extends string & keyof T +> = '' extends Exposed ? T : Pick + // public properties exposed on the proxy, which is used as the render context // in templates (as `this` in the render option) export type ComponentPublicInstance< @@ -192,7 +197,7 @@ export type ComponentPublicInstance< Defaults = {}, MakeDefaultsOptional extends boolean = false, Options = ComponentOptionsBase, - Exposed extends string = string + Exposed extends string = '' > = { $: ComponentInternalInstance $data: D @@ -214,12 +219,15 @@ export type ComponentPublicInstance< cb: Function, options?: WatchOptions ): WatchStopHandle -} & P & - ShallowUnwrapRef & - D & - ExtractComputedReturns & - M & - ComponentCustomProperties +} & ExposedKeys< + P & + ShallowUnwrapRef & + D & + ExtractComputedReturns & + M & + ComponentCustomProperties, + Exposed +> type PublicPropertiesMap = Record any> diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index 13b98edf74b..876d9822228 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -998,6 +998,30 @@ describe('directive typing', () => { expect(comp.directives!.customDirective) }) +describe('expose typing', () => { + const Comp = defineComponent({ + expose: ['a', 'b'], + props: { + some: String + }, + data() { + return { a: 1, b: '2', c: 1 } + } + }) + + expect>(Comp.expose!) + + const vm = new Comp() + // internal should still be exposed + vm.$props + + expectType(vm.a) + expectType(vm.b) + + // @ts-expect-error shouldn't be exposed + vm.c +}) + // check if defineComponent can be exported export default { // function components From 5f49e9c11eb8565d5ca99f13d00f3f81f0801d0b Mon Sep 17 00:00:00 2001 From: pikax Date: Tue, 9 Mar 2021 12:24:33 +0000 Subject: [PATCH 18/42] chore: add global directive type --- packages/runtime-core/src/apiDefineComponent.ts | 9 ++++----- packages/runtime-core/src/index.ts | 3 ++- test-dts/componentTypeExtensions.test-d.tsx | 7 ++++++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 92f1a750a23..36a296eea04 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -12,7 +12,8 @@ import { SetupContext, AllowedComponentProps, ComponentCustomProps, - Component + Component, + ComponentCustomDirectives } from './component' import { ExtractPropTypes, @@ -32,8 +33,6 @@ export type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps -// TODO add Com - export type DefineComponent< PropsOrPropOptions = {}, RawBindings = {}, @@ -64,7 +63,7 @@ export type DefineComponent< Defaults, true, LC, - Directives, + Directives & ComponentCustomDirectives, Exposed > & Props @@ -80,7 +79,7 @@ export type DefineComponent< E, EE, LC, - Directives, + Directives & ComponentCustomDirectives, Exposed, Defaults > & diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 98ba289f565..4940edf8d3a 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -166,7 +166,8 @@ export { ComponentInternalInstance, SetupContext, ComponentCustomProps, - AllowedComponentProps + AllowedComponentProps, + ComponentCustomDirectives } from './component' export { DefineComponent } from './apiDefineComponent' export { diff --git a/test-dts/componentTypeExtensions.test-d.tsx b/test-dts/componentTypeExtensions.test-d.tsx index 32a72f844e6..3dbce81a506 100644 --- a/test-dts/componentTypeExtensions.test-d.tsx +++ b/test-dts/componentTypeExtensions.test-d.tsx @@ -1,10 +1,14 @@ -import { defineComponent, expectError, expectType } from './index' +import { defineComponent, Directive, expectError, expectType } from './index' declare module '@vue/runtime-core' { interface ComponentCustomOptions { test?(n: number): void } + interface ComponentCustomDirectives { + test: Directive + } + interface ComponentCustomProperties { state: 'stopped' | 'running' } @@ -41,6 +45,7 @@ export const Custom = defineComponent({ } }) +expectType(Custom.directives!.test) expectType() expectType() expectType() From fbb62bc0c9ee2aab4d10ec1314e15abb84a1056d Mon Sep 17 00:00:00 2001 From: pikax Date: Tue, 9 Mar 2021 12:41:47 +0000 Subject: [PATCH 19/42] chore: fix tests --- packages/runtime-core/src/componentOptions.ts | 18 +++++++++++++++--- .../src/componentPublicInstance.ts | 3 +++ test-dts/defineComponent.test-d.tsx | 2 ++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index f93cf9daa4c..79b0ec2e075 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -346,7 +346,20 @@ export type ComponentOptions< LC extends Record = {}, Directives extends Record = {}, Exposed extends string = string -> = ComponentOptionsBase & +> = ComponentOptionsBase< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + string, + LC, + Directives, + Exposed +> & ThisType< CreateComponentPublicInstance< {}, @@ -361,8 +374,7 @@ export type ComponentOptions< {}, false, LC, - Directives, - Exposed + Directives > > diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index e77832a7bb1..1fb18e0670b 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -83,6 +83,9 @@ type MixinToOptionTypes = T extends ComponentOptionsBase< infer Extends, any, any, + any, + any, + any, infer Defaults > ? OptionTypesType

& diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index 876d9822228..4e810e47a64 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -718,6 +718,8 @@ describe('extends with mixins', () => { // Test TSX expectType() + expectType() + // mP1, mP2, p1, and p2 have default value. these are not required expectType() From b10bc7750eb60107a74eebee3dea14b6eb1e9dba Mon Sep 17 00:00:00 2001 From: pikax Date: Wed, 10 Mar 2021 08:11:17 +0000 Subject: [PATCH 20/42] chore: clean dup code --- test-dts/defineComponent.test-d.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index 4e810e47a64..876d9822228 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -718,8 +718,6 @@ describe('extends with mixins', () => { // Test TSX expectType() - expectType() - // mP1, mP2, p1, and p2 have default value. these are not required expectType() From d0b13fa681a3266c724582b297786a928659713a Mon Sep 17 00:00:00 2001 From: pikax Date: Thu, 11 Mar 2021 16:30:04 +0000 Subject: [PATCH 21/42] chore: add GlobalComponents and GlobalDirectives --- .../runtime-core/src/apiDefineComponent.ts | 11 ++++--- packages/runtime-core/src/component.ts | 31 ++++++++++++++++++- packages/runtime-core/src/componentOptions.ts | 1 - packages/runtime-core/src/index.ts | 3 +- test-dts/componentTypeExtensions.test-d.tsx | 15 +++++++-- test-dts/defineComponent.test-d.tsx | 6 ++-- 6 files changed, 54 insertions(+), 13 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 36a296eea04..449140ed326 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -13,7 +13,8 @@ import { AllowedComponentProps, ComponentCustomProps, Component, - ComponentCustomDirectives + GlobalDirectives, + GlobalComponents } from './component' import { ExtractPropTypes, @@ -62,8 +63,8 @@ export type DefineComponent< PP & Props, Defaults, true, - LC, - Directives & ComponentCustomDirectives, + LC & GlobalComponents, + Directives & GlobalDirectives, Exposed > & Props @@ -78,8 +79,8 @@ export type DefineComponent< Extends, E, EE, - LC, - Directives & ComponentCustomDirectives, + LC & GlobalComponents, + Directives & GlobalDirectives, Exposed, Defaults > & diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index a8b34e1da00..52e90d263c6 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -64,8 +64,37 @@ export interface ComponentCustomProps {} /** * For globally defined Directives + * Here is an example of adding a directive `VTooltip` as global directive: + * + * @example + * ```ts + * import VTooltip from 'v-tooltip' + * + * declare module '@vue/runtime-core' { + * interface GlobalDirectives { + * VTooltip + * } + * } + * ``` */ -export interface ComponentCustomDirectives extends Record {} +export interface GlobalDirectives extends Record {} + +/** + * For globally defined Components + * Here is an example of adding a component `RouterView` as global component: + * + * @example + * ```ts + * import { RouterView } from 'vue-router' + * + * declare module '@vue/runtime-core' { + * interface GlobalComponents { + * RouterView + * } + * } + * ``` + */ +export interface GlobalComponents extends Record {} /** * Default allowed non-declared props on component in TSX diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 79b0ec2e075..5764d998bb2 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -131,7 +131,6 @@ export interface ComponentOptionsBase< directives?: Directives inheritAttrs?: boolean emits?: (E | EE[]) & ThisType - // TODO infer public instance type based on exposed keys expose?: Exposed[] serverPrefetch?(): Promise diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 4940edf8d3a..ff38b75f039 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -167,7 +167,8 @@ export { SetupContext, ComponentCustomProps, AllowedComponentProps, - ComponentCustomDirectives + GlobalComponents, + GlobalDirectives } from './component' export { DefineComponent } from './apiDefineComponent' export { diff --git a/test-dts/componentTypeExtensions.test-d.tsx b/test-dts/componentTypeExtensions.test-d.tsx index 3dbce81a506..46da0724f9c 100644 --- a/test-dts/componentTypeExtensions.test-d.tsx +++ b/test-dts/componentTypeExtensions.test-d.tsx @@ -1,14 +1,24 @@ -import { defineComponent, Directive, expectError, expectType } from './index' +import { + defineComponent, + DefineComponent, + Directive, + expectError, + expectType +} from './index' declare module '@vue/runtime-core' { interface ComponentCustomOptions { test?(n: number): void } - interface ComponentCustomDirectives { + interface GlobalDirectives { test: Directive } + interface GlobalComponents { + RouterView: DefineComponent<{}> + } + interface ComponentCustomProperties { state: 'stopped' | 'running' } @@ -46,6 +56,7 @@ export const Custom = defineComponent({ }) expectType(Custom.directives!.test) +expectType>(Custom.components!.RouterView) expectType() expectType() expectType() diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index 876d9822228..4fcf771c7a3 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -978,7 +978,7 @@ describe('expose component types', () => { } }) - expect(parent.components!.child) + expectType(parent.components!.child) }) describe('directive typing', () => { @@ -995,7 +995,7 @@ describe('directive typing', () => { } }) - expect(comp.directives!.customDirective) + expectType(comp.directives!.customDirective) }) describe('expose typing', () => { @@ -1009,7 +1009,7 @@ describe('expose typing', () => { } }) - expect>(Comp.expose!) + expectType>(Comp.expose!) const vm = new Comp() // internal should still be exposed From 057bad9f64a8b93167c2d3b1e005010b9808aadc Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 13 Mar 2021 08:41:57 +0000 Subject: [PATCH 22/42] chore: add Suspense, KeepAlive, Teleport to GlobalComponents --- packages/runtime-core/src/index.ts | 19 +++++++++++++++++-- .../runtime-core/types/globalComponents.d.ts | 10 ++++++++++ test-dts/defineComponent.test-d.tsx | 9 +++++++-- 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 packages/runtime-core/types/globalComponents.d.ts diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index ff38b75f039..c7a5d7ac776 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -118,6 +118,21 @@ declare module '@vue/reactivity' { } } +// Augment GlobalComponents +// Note: if updating this, also update `types/globalComponents.d.ts`. +import { TeleportProps } from './components/Teleport' +import { SuspenseProps } from './components/Suspense' +import { KeepAliveProps } from './components/KeepAlive' +import { DefineComponent } from './apiDefineComponent' + +declare module '@vue/runtime-core' { + export interface GlobalComponents { + Teleport: DefineComponent + Suspense: DefineComponent + KeepAlive: DefineComponent + } +} + export { ReactiveEffect, ReactiveEffectOptions, @@ -167,8 +182,8 @@ export { SetupContext, ComponentCustomProps, AllowedComponentProps, - GlobalComponents, - GlobalDirectives + GlobalDirectives, + GlobalComponents } from './component' export { DefineComponent } from './apiDefineComponent' export { diff --git a/packages/runtime-core/types/globalComponents.d.ts b/packages/runtime-core/types/globalComponents.d.ts new file mode 100644 index 00000000000..d3cd069e6c4 --- /dev/null +++ b/packages/runtime-core/types/globalComponents.d.ts @@ -0,0 +1,10 @@ +// Note: this file is auto concatenated to the end of the bundled d.ts during +// build. + +declare module '@vue/runtime-core' { + export interface GlobalComponents { + Teleport: DefineComponent + Suspense: DefineComponent + KeepAlive: DefineComponent + } +} diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index 4fcf771c7a3..46676c98c31 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -12,7 +12,8 @@ import { ComponentOptions, SetupContext, h, - Directive + Directive, + KeepAliveProps } from './index' describe('with object props', () => { @@ -979,6 +980,10 @@ describe('expose component types', () => { }) expectType(parent.components!.child) + + // global components + expectType(new parent.components!.KeepAlive().$props) + expectType(new child.components!.KeepAlive().$props) }) describe('directive typing', () => { @@ -1009,7 +1014,7 @@ describe('expose typing', () => { } }) - expectType>(Comp.expose!) + expect>(Comp.expose!) const vm = new Comp() // internal should still be exposed From 9970b4510b46fd3fdc9e5a229439e0776fb39517 Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 13 Mar 2021 09:12:30 +0000 Subject: [PATCH 23/42] chore: add Transition and TransitionGroup to globalComponents --- packages/runtime-dom/src/index.ts | 13 ++++++++++++- packages/runtime-dom/types/globalComponents.d.ts | 9 +++++++++ test-dts/defineComponent.test-d.tsx | 7 ++++++- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 packages/runtime-dom/types/globalComponents.d.ts diff --git a/packages/runtime-dom/src/index.ts b/packages/runtime-dom/src/index.ts index 773470621fe..bd47e96d800 100644 --- a/packages/runtime-dom/src/index.ts +++ b/packages/runtime-dom/src/index.ts @@ -8,12 +8,15 @@ import { HydrationRenderer, App, RootHydrateFunction, - isRuntimeOnly + isRuntimeOnly, + DefineComponent } from '@vue/runtime-core' import { nodeOps } from './nodeOps' import { patchProp, forcePatchProp } from './patchProp' // Importing from the compiler, will be tree-shaken in prod import { isFunction, isString, isHTMLTag, isSVGTag, extend } from '@vue/shared' +import { TransitionProps } from './components/Transition' +import { TransitionGroupProps } from './components/TransitionGroup' declare module '@vue/reactivity' { export interface RefUnwrapBailTypes { @@ -22,6 +25,14 @@ declare module '@vue/reactivity' { } } +declare module '@vue/runtime-core' { + interface GlobalComponents { + // Note: if updating this, also update `types/globalComponents.d.ts`. + Transition: DefineComponent + TransitionGroup: DefineComponent + } +} + const rendererOptions = extend({ patchProp, forcePatchProp }, nodeOps) // lazy create the renderer - this makes core renderer logic tree-shakable diff --git a/packages/runtime-dom/types/globalComponents.d.ts b/packages/runtime-dom/types/globalComponents.d.ts new file mode 100644 index 00000000000..025e76bb30a --- /dev/null +++ b/packages/runtime-dom/types/globalComponents.d.ts @@ -0,0 +1,9 @@ +// Note: this file is auto concatenated to the end of the bundled d.ts during +// build. + +declare module '@vue/runtime-core' { + interface GlobalComponents { + Transition: DefineComponent + TransitionGroup: DefineComponent + } +} diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index 46676c98c31..1abd3f955ea 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -13,7 +13,8 @@ import { SetupContext, h, Directive, - KeepAliveProps + KeepAliveProps, + TransitionProps } from './index' describe('with object props', () => { @@ -984,6 +985,10 @@ describe('expose component types', () => { // global components expectType(new parent.components!.KeepAlive().$props) expectType(new child.components!.KeepAlive().$props) + + // runtime-dom components + expectType(new parent.components!.Transition().$props) + expectType(new parent.components!.Transition().$props) }) describe('directive typing', () => { From 2498929394e8d8d9c08ce01c30c4861046a457e9 Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 13 Mar 2021 09:18:25 +0000 Subject: [PATCH 24/42] chore: add BaseTransition ass globalComponent --- packages/runtime-core/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index c7a5d7ac776..a1b5edf93aa 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -123,6 +123,7 @@ declare module '@vue/reactivity' { import { TeleportProps } from './components/Teleport' import { SuspenseProps } from './components/Suspense' import { KeepAliveProps } from './components/KeepAlive' +import { BaseTransitionProps } from './components/BaseTransition' import { DefineComponent } from './apiDefineComponent' declare module '@vue/runtime-core' { @@ -130,6 +131,7 @@ declare module '@vue/runtime-core' { Teleport: DefineComponent Suspense: DefineComponent KeepAlive: DefineComponent + BaseTransition: DefineComponent } } From b792c6c9f8ab42708d90b861f38034c4d5445062 Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 13 Mar 2021 09:24:19 +0000 Subject: [PATCH 25/42] chore: add VShow as a globalDirective --- packages/runtime-dom/src/index.ts | 5 +++++ packages/runtime-dom/types/globalComponents.d.ts | 5 ++--- packages/runtime-dom/types/globalDirectives.d.ts | 9 +++++++++ test-dts/defineComponent.test-d.tsx | 6 +++++- 4 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 packages/runtime-dom/types/globalDirectives.d.ts diff --git a/packages/runtime-dom/src/index.ts b/packages/runtime-dom/src/index.ts index bd47e96d800..3e2e736342c 100644 --- a/packages/runtime-dom/src/index.ts +++ b/packages/runtime-dom/src/index.ts @@ -17,6 +17,7 @@ import { patchProp, forcePatchProp } from './patchProp' import { isFunction, isString, isHTMLTag, isSVGTag, extend } from '@vue/shared' import { TransitionProps } from './components/Transition' import { TransitionGroupProps } from './components/TransitionGroup' +import { vShow } from './directives/vShow' declare module '@vue/reactivity' { export interface RefUnwrapBailTypes { @@ -31,6 +32,10 @@ declare module '@vue/runtime-core' { Transition: DefineComponent TransitionGroup: DefineComponent } + + interface GlobalDirectives { + vShow: typeof vShow + } } const rendererOptions = extend({ patchProp, forcePatchProp }, nodeOps) diff --git a/packages/runtime-dom/types/globalComponents.d.ts b/packages/runtime-dom/types/globalComponents.d.ts index 025e76bb30a..041d85e90fb 100644 --- a/packages/runtime-dom/types/globalComponents.d.ts +++ b/packages/runtime-dom/types/globalComponents.d.ts @@ -2,8 +2,7 @@ // build. declare module '@vue/runtime-core' { - interface GlobalComponents { - Transition: DefineComponent - TransitionGroup: DefineComponent + interface GlobalDirectives { + vShow: typeof vShow } } diff --git a/packages/runtime-dom/types/globalDirectives.d.ts b/packages/runtime-dom/types/globalDirectives.d.ts new file mode 100644 index 00000000000..025e76bb30a --- /dev/null +++ b/packages/runtime-dom/types/globalDirectives.d.ts @@ -0,0 +1,9 @@ +// Note: this file is auto concatenated to the end of the bundled d.ts during +// build. + +declare module '@vue/runtime-core' { + interface GlobalComponents { + Transition: DefineComponent + TransitionGroup: DefineComponent + } +} diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index 1abd3f955ea..9ee7cd6fe8a 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -14,7 +14,8 @@ import { h, Directive, KeepAliveProps, - TransitionProps + TransitionProps, + vShow } from './index' describe('with object props', () => { @@ -1006,6 +1007,9 @@ describe('directive typing', () => { }) expectType(comp.directives!.customDirective) + + // global directive + expectType(comp.directives!.vShow) }) describe('expose typing', () => { From 980dbf3c26d602766ee2aceceaf0d8a4fb5796ee Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 13 Mar 2021 14:28:02 +0000 Subject: [PATCH 26/42] chore: add BaseTransition --- packages/runtime-core/types/globalComponents.d.ts | 1 + packages/runtime-dom/types/globalDirectives.d.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/runtime-core/types/globalComponents.d.ts b/packages/runtime-core/types/globalComponents.d.ts index d3cd069e6c4..a4abd6d1fff 100644 --- a/packages/runtime-core/types/globalComponents.d.ts +++ b/packages/runtime-core/types/globalComponents.d.ts @@ -6,5 +6,6 @@ declare module '@vue/runtime-core' { Teleport: DefineComponent Suspense: DefineComponent KeepAlive: DefineComponent + BaseTransition: DefineComponent } } diff --git a/packages/runtime-dom/types/globalDirectives.d.ts b/packages/runtime-dom/types/globalDirectives.d.ts index 025e76bb30a..28d1bfc87c4 100644 --- a/packages/runtime-dom/types/globalDirectives.d.ts +++ b/packages/runtime-dom/types/globalDirectives.d.ts @@ -1,6 +1,7 @@ // Note: this file is auto concatenated to the end of the bundled d.ts during // build. +import { DefineComponent } from '@vue/runtime-core' declare module '@vue/runtime-core' { interface GlobalComponents { Transition: DefineComponent From d729fba0b9ed33660ec64997b3858b663a910766 Mon Sep 17 00:00:00 2001 From: pikax Date: Sat, 13 Mar 2021 15:58:57 +0000 Subject: [PATCH 27/42] chore: added support for `h` --- packages/runtime-core/src/component.ts | 9 ++-- .../src/componentPublicInstance.ts | 2 +- packages/runtime-core/src/componentSlots.ts | 25 ++++----- packages/runtime-core/src/h.ts | 10 ++-- test-dts/defineComponent.test-d.tsx | 51 +++++++++++++++++-- 5 files changed, 70 insertions(+), 27 deletions(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index f16ffeef100..41189f4d61d 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -99,10 +99,13 @@ export interface ComponentInternalOptions { __file?: string } -export interface FunctionalComponent

- extends ComponentInternalOptions { +export interface FunctionalComponent< + P = {}, + E extends EmitsOptions = {}, + S extends Slots = Slots +> extends ComponentInternalOptions { // use of any here is intentional so it can be a valid JSX Element constructor - (props: P, ctx: Omit, 'expose'>): any + (props: P, ctx: Omit, 'expose'>): any props?: ComponentPropsOptions

emits?: E | (keyof E)[] inheritAttrs?: boolean diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 00bbbaf2f00..30c8419ce6c 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -195,7 +195,7 @@ export type ComponentPublicInstance< : P & PublicProps $attrs: Data $refs: Data - $slots: Slots + $slots: Slots $root: ComponentPublicInstance | null $parent: ComponentPublicInstance | null $emit: EmitFn diff --git a/packages/runtime-core/src/componentSlots.ts b/packages/runtime-core/src/componentSlots.ts index b3cbd2b49ed..1a2fe2badba 100644 --- a/packages/runtime-core/src/componentSlots.ts +++ b/packages/runtime-core/src/componentSlots.ts @@ -33,20 +33,14 @@ export type SlotArray = V extends PropertyKey ? Record : Record -export type Slots = unknown extends T - ? Readonly>> - : T extends Array ? Readonly> : Readonly> - -// export type Slot = (...args: any[]) => VNode[] - -// export type InternalSlots = { -// [name: string]: Slot | undefined -// } - -// export type Slots = Readonly - -export type RawSlots = { - [name: string]: unknown +export type Slots = RenderSlot & + (unknown extends T + ? Readonly>> + : T extends Array + ? Readonly> + : Readonly>) + +export type RenderSlot = { // manual render fn hint to skip forced children updates $stable?: boolean /** @@ -65,6 +59,9 @@ export type RawSlots = { */ _?: SlotFlags } +export type RawSlots = { + [name: string]: unknown +} & RenderSlot const isInternalKey = (key: string) => key[0] === '_' || key === '$stable' diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index cb87cf6ee3c..1f67ed4fd0d 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -66,11 +66,11 @@ type RawChildren = | (() => any) // fake constructor type returned from `defineComponent` -interface Constructor

{ +interface Constructor

{ __isFragment?: never __isTeleport?: never __isSuspense?: never - new (...args: any[]): { $props: P } + new (...args: any[]): { $props: P; $slots?: S } } // The following is a series of overloads for providing props validation of @@ -144,10 +144,10 @@ export function h

( // fake constructor type returned by `defineComponent` or class component export function h(type: Constructor, children?: RawChildren): VNode -export function h

( - type: Constructor

, +export function h( + type: Constructor, props?: (RawProps & P) | ({} extends P ? null : never), - children?: RawChildren | RawSlots + children?: (RawChildren & S) | ({} extends S ? RawSlots : S) ): VNode // fake constructor type returned by `defineComponent` diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index 0ec0cf0d045..4f8a979108c 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -964,9 +964,9 @@ describe('async setup', () => { }) describe('typed slots', () => { - const xxx = defineComponent({ + const Comp = defineComponent({ slots: { - test: null as Partial, + test: null, item: Object as () => { item: { value: number }; i: number } }, @@ -978,14 +978,57 @@ describe('typed slots', () => { value: 22 } }) + // @ts-expect-error missing item prop + expectError(slots.item!({ i: 22 })) + } + }) + + h( + Comp, + {}, + { + // @ts-expect-error no argument expected + test(x) {}, + item(s) { + expectType(s.i) + expectType<{ value: number }>(s.item) + } + } + ) +}) + +describe('typed slots just type', () => { + const Comp = defineComponent({ + slots: {} as { + test: null + item: { item: { value: number }; i: number } + }, + setup(_, { slots }) { + slots.test!() + slots.item!({ + i: 22, + item: { + value: 22 + } + }) // @ts-expect-error missing item prop expectError(slots.item!({ i: 22 })) } }) - // TODO add to `h` - h(xxx, {}, {}) + h( + Comp, + {}, + { + // @ts-expect-error no argument expected + test(x) {}, + item(s) { + expectType(s.i) + expectType<{ value: number }>(s.item) + } + } + ) }) // check if defineComponent can be exported From 200838d6edfb0f59f08e2bf69a463e433a05648b Mon Sep 17 00:00:00 2001 From: pikax Date: Sun, 14 Mar 2021 09:23:23 +0000 Subject: [PATCH 28/42] chore: correct interface with file name --- packages/runtime-dom/types/globalComponents.d.ts | 6 ++++-- packages/runtime-dom/types/globalDirectives.d.ts | 6 ++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/runtime-dom/types/globalComponents.d.ts b/packages/runtime-dom/types/globalComponents.d.ts index 041d85e90fb..28d1bfc87c4 100644 --- a/packages/runtime-dom/types/globalComponents.d.ts +++ b/packages/runtime-dom/types/globalComponents.d.ts @@ -1,8 +1,10 @@ // Note: this file is auto concatenated to the end of the bundled d.ts during // build. +import { DefineComponent } from '@vue/runtime-core' declare module '@vue/runtime-core' { - interface GlobalDirectives { - vShow: typeof vShow + interface GlobalComponents { + Transition: DefineComponent + TransitionGroup: DefineComponent } } diff --git a/packages/runtime-dom/types/globalDirectives.d.ts b/packages/runtime-dom/types/globalDirectives.d.ts index 28d1bfc87c4..041d85e90fb 100644 --- a/packages/runtime-dom/types/globalDirectives.d.ts +++ b/packages/runtime-dom/types/globalDirectives.d.ts @@ -1,10 +1,8 @@ // Note: this file is auto concatenated to the end of the bundled d.ts during // build. -import { DefineComponent } from '@vue/runtime-core' declare module '@vue/runtime-core' { - interface GlobalComponents { - Transition: DefineComponent - TransitionGroup: DefineComponent + interface GlobalDirectives { + vShow: typeof vShow } } From 08c121785acc4a388f9854c384f580f1c416c315 Mon Sep 17 00:00:00 2001 From: pikax Date: Tue, 30 Mar 2021 16:28:20 +0100 Subject: [PATCH 29/42] chore: wrap component to get the type --- packages/server-renderer/__tests__/render.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server-renderer/__tests__/render.spec.ts b/packages/server-renderer/__tests__/render.spec.ts index 67bc23450b8..f01aef06793 100644 --- a/packages/server-renderer/__tests__/render.spec.ts +++ b/packages/server-renderer/__tests__/render.spec.ts @@ -834,11 +834,11 @@ function testRender(type: string, render: typeof renderToString) { await render( createApp({ components: { - A: { + A: defineComponent({ ssrRender(_ctx, _push) { _push(`

A
`) } - }, + }), B: { render: () => h('div', 'B') } From ca63ffa174ce88865d1ae2b5368e718c49185d51 Mon Sep 17 00:00:00 2001 From: pikax Date: Thu, 15 Apr 2021 19:02:45 +0100 Subject: [PATCH 30/42] chore: typed directives + VModel directive --- packages/runtime-core/src/directives.ts | 43 +++++++++++++------ packages/runtime-dom/src/directives/vModel.ts | 12 ++++-- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/packages/runtime-core/src/directives.ts b/packages/runtime-core/src/directives.ts index 20f25d03ee9..5442dc890fe 100644 --- a/packages/runtime-core/src/directives.ts +++ b/packages/runtime-core/src/directives.ts @@ -19,18 +19,28 @@ import { currentRenderingInstance } from './componentRenderContext' import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling' import { ComponentPublicInstance } from './componentPublicInstance' -export interface DirectiveBinding { +export interface DirectiveBinding< + V = any, + Arg extends string = string, + Modifiers extends string = string +> { instance: ComponentPublicInstance | null value: V oldValue: V | null - arg?: string - modifiers: DirectiveModifiers + arg?: Arg + modifiers: DirectiveModifiers dir: ObjectDirective } -export type DirectiveHook | null, V = any> = ( +export type DirectiveHook< + T = any, + Prev = VNode | null, + V = any, + Arg extends string = string, + Modifiers extends string = string +> = ( el: T, - binding: DirectiveBinding, + binding: DirectiveBinding, vnode: VNode, prevVNode: Prev ) => void @@ -40,14 +50,19 @@ export type SSRDirectiveHook = ( vnode: VNode ) => Data | undefined -export interface ObjectDirective { - created?: DirectiveHook - beforeMount?: DirectiveHook - mounted?: DirectiveHook - beforeUpdate?: DirectiveHook, V> - updated?: DirectiveHook, V> - beforeUnmount?: DirectiveHook - unmounted?: DirectiveHook +export interface ObjectDirective< + T = any, + V = any, + Arg extends string = string, + Modifiers extends string = string +> { + created?: DirectiveHook + beforeMount?: DirectiveHook + mounted?: DirectiveHook + beforeUpdate?: DirectiveHook, V, Arg, Modifiers> + updated?: DirectiveHook, V, Arg, Modifiers> + beforeUnmount?: DirectiveHook + unmounted?: DirectiveHook getSSRProps?: SSRDirectiveHook } @@ -57,7 +72,7 @@ export type Directive = | ObjectDirective | FunctionDirective -export type DirectiveModifiers = Record +export type DirectiveModifiers = Record const isBuiltInDirective = /*#__PURE__*/ makeMap( 'bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text' diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts index a90c4466a17..1894d8e65a7 100644 --- a/packages/runtime-dom/src/directives/vModel.ts +++ b/packages/runtime-dom/src/directives/vModel.ts @@ -40,12 +40,18 @@ function trigger(el: HTMLElement, type: string) { el.dispatchEvent(e) } -type ModelDirective = ObjectDirective +type ModelDirective = ObjectDirective< + T & { _assign: AssignerFn }, + any, + string, + Modifiers +> // We are exporting the v-model runtime directly as vnode hooks so that it can // be tree-shaken in case v-model is never used. export const vModelText: ModelDirective< - HTMLInputElement | HTMLTextAreaElement + HTMLInputElement | HTMLTextAreaElement, + 'trim' | 'number' | 'lazy' > = { created(el, { modifiers: { lazy, trim, number } }, vnode) { el._assign = getModelAssigner(vnode) @@ -170,7 +176,7 @@ export const vModelRadio: ModelDirective = { } } -export const vModelSelect: ModelDirective = { +export const vModelSelect: ModelDirective = { created(el, { value, modifiers: { number } }, vnode) { const isSetModel = isSet(value) addEventListener(el, 'change', () => { From 16352ca65cdad5787c145113d328123fa72379da Mon Sep 17 00:00:00 2001 From: pikax Date: Sun, 18 Apr 2021 09:52:45 +0100 Subject: [PATCH 31/42] chore: move arg after modifiers and add tests --- packages/runtime-core/src/directives.ts | 80 ++++++++++++------- packages/runtime-dom/src/directives/vModel.ts | 1 - test-dts/directives.test-d.ts | 47 +++++++++++ 3 files changed, 98 insertions(+), 30 deletions(-) create mode 100644 test-dts/directives.test-d.ts diff --git a/packages/runtime-core/src/directives.ts b/packages/runtime-core/src/directives.ts index 5442dc890fe..772316872b8 100644 --- a/packages/runtime-core/src/directives.ts +++ b/packages/runtime-core/src/directives.ts @@ -20,28 +20,28 @@ import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling' import { ComponentPublicInstance } from './componentPublicInstance' export interface DirectiveBinding< - V = any, - Arg extends string = string, - Modifiers extends string = string + Value = any, + Modifiers extends string = string, + Arg extends string = string > { instance: ComponentPublicInstance | null - value: V - oldValue: V | null + value: Value + oldValue: Value | null arg?: Arg modifiers: DirectiveModifiers - dir: ObjectDirective + dir: ObjectDirective } export type DirectiveHook< - T = any, - Prev = VNode | null, - V = any, - Arg extends string = string, - Modifiers extends string = string + HostElement = any, + Prev = VNode | null, + Value = any, + Modifiers extends string = string, + Arg extends string = string > = ( - el: T, - binding: DirectiveBinding, - vnode: VNode, + el: HostElement, + binding: DirectiveBinding, + vnode: VNode, prevVNode: Prev ) => void @@ -51,26 +51,48 @@ export type SSRDirectiveHook = ( ) => Data | undefined export interface ObjectDirective< - T = any, - V = any, - Arg extends string = string, - Modifiers extends string = string + HostElement = any, + Value = any, + Modifiers extends string = string, + Arg extends string = string > { - created?: DirectiveHook - beforeMount?: DirectiveHook - mounted?: DirectiveHook - beforeUpdate?: DirectiveHook, V, Arg, Modifiers> - updated?: DirectiveHook, V, Arg, Modifiers> - beforeUnmount?: DirectiveHook - unmounted?: DirectiveHook + created?: DirectiveHook + beforeMount?: DirectiveHook + mounted?: DirectiveHook + beforeUpdate?: DirectiveHook< + HostElement, + VNode, + Value, + Arg, + Modifiers + > + updated?: DirectiveHook< + HostElement, + VNode, + Value, + Arg, + Modifiers + > + beforeUnmount?: DirectiveHook + unmounted?: DirectiveHook getSSRProps?: SSRDirectiveHook } -export type FunctionDirective = DirectiveHook +export type FunctionDirective< + HostElement = any, + V = any, + Modifiers extends string = string, + Arg extends string = string +> = DirectiveHook -export type Directive = - | ObjectDirective - | FunctionDirective +export type Directive< + HostElement = any, + Value = any, + Modifiers extends string = string, + Arg extends string = string +> = + | ObjectDirective + | FunctionDirective export type DirectiveModifiers = Record diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts index 1894d8e65a7..14f3e9ea473 100644 --- a/packages/runtime-dom/src/directives/vModel.ts +++ b/packages/runtime-dom/src/directives/vModel.ts @@ -43,7 +43,6 @@ function trigger(el: HTMLElement, type: string) { type ModelDirective = ObjectDirective< T & { _assign: AssignerFn }, any, - string, Modifiers > diff --git a/test-dts/directives.test-d.ts b/test-dts/directives.test-d.ts new file mode 100644 index 00000000000..d6ec3d15854 --- /dev/null +++ b/test-dts/directives.test-d.ts @@ -0,0 +1,47 @@ +import { Directive, expectError, expectType } from './index' + +type ExtractBinding = T extends ( + el: any, + binding: infer B, + vnode: any, + prev: any +) => any + ? B + : never + +declare function testDirective< + Value, + Modifiers extends string = string, + Arg extends string = string +>(): ExtractBinding> + +expectType<{ + value: number + oldValue: number | null + arg?: 'Arg' + modifiers: Record<'a' | 'b', boolean> +}>(testDirective()) + +expectError<{ + value: number + oldValue: number | null + arg?: 'Arg' + modifiers: Record<'a' | 'b', boolean> + // @ts-expect-error +}>(testDirective()) + +expectType<{ + value: number + oldValue: number | null + arg?: 'Arg' + modifiers: Record<'a' | 'b', boolean> + // @ts-expect-error +}>(testDirective()) + +expectType<{ + value: number + oldValue: number | null + arg?: 'Arg' + modifiers: Record<'a' | 'b', boolean> + // @ts-expect-error +}>(testDirective()) From 7754d7eed73f8993c7df6f27d26052e3df4fd773 Mon Sep 17 00:00:00 2001 From: pikax Date: Sun, 18 Apr 2021 10:10:12 +0100 Subject: [PATCH 32/42] chore: improve tests --- packages/runtime-core/src/directives.ts | 26 +++++----- test-dts/directives.test-d.ts | 69 ++++++++++++++----------- 2 files changed, 53 insertions(+), 42 deletions(-) diff --git a/packages/runtime-core/src/directives.ts b/packages/runtime-core/src/directives.ts index 772316872b8..4bc63050c7d 100644 --- a/packages/runtime-core/src/directives.ts +++ b/packages/runtime-core/src/directives.ts @@ -40,7 +40,7 @@ export type DirectiveHook< Arg extends string = string > = ( el: HostElement, - binding: DirectiveBinding, + binding: DirectiveBinding, vnode: VNode, prevVNode: Prev ) => void @@ -56,25 +56,25 @@ export interface ObjectDirective< Modifiers extends string = string, Arg extends string = string > { - created?: DirectiveHook - beforeMount?: DirectiveHook - mounted?: DirectiveHook + created?: DirectiveHook + beforeMount?: DirectiveHook + mounted?: DirectiveHook beforeUpdate?: DirectiveHook< HostElement, VNode, Value, - Arg, - Modifiers + Modifiers, + Arg > updated?: DirectiveHook< HostElement, VNode, Value, - Arg, - Modifiers + Modifiers, + Arg > - beforeUnmount?: DirectiveHook - unmounted?: DirectiveHook + beforeUnmount?: DirectiveHook + unmounted?: DirectiveHook getSSRProps?: SSRDirectiveHook } @@ -83,7 +83,7 @@ export type FunctionDirective< V = any, Modifiers extends string = string, Arg extends string = string -> = DirectiveHook +> = DirectiveHook export type Directive< HostElement = any, @@ -91,8 +91,8 @@ export type Directive< Modifiers extends string = string, Arg extends string = string > = - | ObjectDirective - | FunctionDirective + | ObjectDirective + | FunctionDirective export type DirectiveModifiers = Record diff --git a/test-dts/directives.test-d.ts b/test-dts/directives.test-d.ts index d6ec3d15854..700c9727292 100644 --- a/test-dts/directives.test-d.ts +++ b/test-dts/directives.test-d.ts @@ -1,4 +1,5 @@ -import { Directive, expectError, expectType } from './index' +import { ObjectDirective } from '@vue/runtime-core' +import { Directive, expectError, expectType, vModelText } from './index' type ExtractBinding = T extends ( el: any, @@ -13,35 +14,45 @@ declare function testDirective< Value, Modifiers extends string = string, Arg extends string = string ->(): ExtractBinding> +>(): ExtractBinding> -expectType<{ - value: number - oldValue: number | null - arg?: 'Arg' - modifiers: Record<'a' | 'b', boolean> -}>(testDirective()) - -expectError<{ - value: number - oldValue: number | null - arg?: 'Arg' - modifiers: Record<'a' | 'b', boolean> +describe('vmodel', () => { + expectType>( + vModelText + ) // @ts-expect-error -}>(testDirective()) + expectType>(vModelText) +}) -expectType<{ - value: number - oldValue: number | null - arg?: 'Arg' - modifiers: Record<'a' | 'b', boolean> - // @ts-expect-error -}>(testDirective()) +describe('custom', () => { + expectType<{ + value: number + oldValue: number | null + arg?: 'Arg' + modifiers: Record<'a' | 'b', boolean> + }>(testDirective()) -expectType<{ - value: number - oldValue: number | null - arg?: 'Arg' - modifiers: Record<'a' | 'b', boolean> - // @ts-expect-error -}>(testDirective()) + expectError<{ + value: number + oldValue: number | null + arg?: 'Arg' + modifiers: Record<'a' | 'b', boolean> + // @ts-expect-error + }>(testDirective()) + + expectType<{ + value: number + oldValue: number | null + arg?: 'Arg' + modifiers: Record<'a' | 'b', boolean> + // @ts-expect-error + }>(testDirective()) + + expectType<{ + value: number + oldValue: number | null + arg?: 'Arg' + modifiers: Record<'a' | 'b', boolean> + // @ts-expect-error + }>(testDirective()) +}) From 6558afdbd43e5069246305da373f506e03498081 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Fri, 23 Apr 2021 11:16:40 +0100 Subject: [PATCH 33/42] chore: add vOn directive as global --- packages/runtime-dom/src/directives/vOn.ts | 52 +++++++++++++--------- packages/runtime-dom/src/index.ts | 2 + 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/packages/runtime-dom/src/directives/vOn.ts b/packages/runtime-dom/src/directives/vOn.ts index ce4a4d0c293..891ef1a6bd6 100644 --- a/packages/runtime-dom/src/directives/vOn.ts +++ b/packages/runtime-dom/src/directives/vOn.ts @@ -1,31 +1,39 @@ import { hyphenate } from '@vue/shared' - -const systemModifiers = ['ctrl', 'shift', 'alt', 'meta'] +import { Directive } from 'test-dts' type KeyedEvent = KeyboardEvent | MouseEvent | TouchEvent -const modifierGuards: Record< - string, - (e: Event, modifiers: string[]) => void | boolean -> = { - stop: e => e.stopPropagation(), - prevent: e => e.preventDefault(), - self: e => e.target !== e.currentTarget, - ctrl: e => !(e as KeyedEvent).ctrlKey, - shift: e => !(e as KeyedEvent).shiftKey, - alt: e => !(e as KeyedEvent).altKey, - meta: e => !(e as KeyedEvent).metaKey, - left: e => 'button' in e && (e as MouseEvent).button !== 0, - middle: e => 'button' in e && (e as MouseEvent).button !== 1, - right: e => 'button' in e && (e as MouseEvent).button !== 2, - exact: (e, modifiers) => +type SystemModifiers = 'ctrl' | 'shift' | 'alt' | 'meta' +type CompatModifiers = keyof typeof keyNames + +export type VOnModifiers = SystemModifiers | ModifierGuards | CompatModifiers + +const systemModifiers: Array = ['ctrl', 'shift', 'alt', 'meta'] + +const modifierGuards = { + stop: (e: Event) => e.stopPropagation(), + prevent: (e: Event) => e.preventDefault(), + self: (e: Event) => e.target !== e.currentTarget, + ctrl: (e: Event) => !(e as KeyedEvent).ctrlKey, + shift: (e: Event) => !(e as KeyedEvent).shiftKey, + alt: (e: Event) => !(e as KeyedEvent).altKey, + meta: (e: Event) => !(e as KeyedEvent).metaKey, + left: (e: Event) => 'button' in e && (e as MouseEvent).button !== 0, + middle: (e: Event) => 'button' in e && (e as MouseEvent).button !== 1, + right: (e: Event) => 'button' in e && (e as MouseEvent).button !== 2, + exact: (e: Event, modifiers: string[]) => systemModifiers.some(m => (e as any)[`${m}Key`] && !modifiers.includes(m)) } +type ModifierGuards = keyof typeof modifierGuards + /** * @private */ -export const withModifiers = (fn: Function, modifiers: string[]) => { +export const withModifiers = ( + fn: Function, + modifiers: Array +) => { return (event: Event, ...args: unknown[]) => { for (let i = 0; i < modifiers.length; i++) { const guard = modifierGuards[modifiers[i]] @@ -37,7 +45,7 @@ export const withModifiers = (fn: Function, modifiers: string[]) => { // Kept for 2.x compat. // Note: IE11 compat for `spacebar` and `del` is removed for now. -const keyNames: Record = { +const keyNames = { esc: 'escape', space: ' ', up: 'arrow-up', @@ -56,10 +64,14 @@ export const withKeys = (fn: Function, modifiers: string[]) => { const eventKey = hyphenate(event.key) if ( // None of the provided key modifiers match the current event key - !modifiers.some(k => k === eventKey || keyNames[k] === eventKey) + !modifiers.some( + k => k === eventKey || keyNames[k as CompatModifiers] === eventKey + ) ) { return } return fn(event) } } + +export type VOnDirective = Directive diff --git a/packages/runtime-dom/src/index.ts b/packages/runtime-dom/src/index.ts index 3e2e736342c..2115d3fadb9 100644 --- a/packages/runtime-dom/src/index.ts +++ b/packages/runtime-dom/src/index.ts @@ -18,6 +18,7 @@ import { isFunction, isString, isHTMLTag, isSVGTag, extend } from '@vue/shared' import { TransitionProps } from './components/Transition' import { TransitionGroupProps } from './components/TransitionGroup' import { vShow } from './directives/vShow' +import { VOnDirective } from './directives/vOn' declare module '@vue/reactivity' { export interface RefUnwrapBailTypes { @@ -35,6 +36,7 @@ declare module '@vue/runtime-core' { interface GlobalDirectives { vShow: typeof vShow + vOn: VOnDirective } } From 99741b8610d680a86ff055d277a6a905b4a7e2e8 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Sun, 25 Apr 2021 14:16:18 +0100 Subject: [PATCH 34/42] chore: vmodel WIP --- packages/runtime-dom/src/directives/vModel.ts | 7 +++++++ packages/runtime-dom/src/index.ts | 11 ++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts index 14f3e9ea473..72507b46458 100644 --- a/packages/runtime-dom/src/directives/vModel.ts +++ b/packages/runtime-dom/src/directives/vModel.ts @@ -325,3 +325,10 @@ if (__NODE_JS__) { } } } + +export type VModelDirective = + | typeof vModelText + | typeof vModelCheckbox + | typeof vModelSelect + | typeof vModelRadio + | typeof vModelDynamic diff --git a/packages/runtime-dom/src/index.ts b/packages/runtime-dom/src/index.ts index 2115d3fadb9..e2223a9364d 100644 --- a/packages/runtime-dom/src/index.ts +++ b/packages/runtime-dom/src/index.ts @@ -9,7 +9,10 @@ import { App, RootHydrateFunction, isRuntimeOnly, - DefineComponent + DefineComponent, + Directive, + Directive, + Directive } from '@vue/runtime-core' import { nodeOps } from './nodeOps' import { patchProp, forcePatchProp } from './patchProp' @@ -19,6 +22,7 @@ import { TransitionProps } from './components/Transition' import { TransitionGroupProps } from './components/TransitionGroup' import { vShow } from './directives/vShow' import { VOnDirective } from './directives/vOn' +import { VModelDirective } from './directives/vModel' declare module '@vue/reactivity' { export interface RefUnwrapBailTypes { @@ -35,8 +39,13 @@ declare module '@vue/runtime-core' { } interface GlobalDirectives { + // Note: if updating this, also update `types/globalDirectives.d.ts`. vShow: typeof vShow vOn: VOnDirective + vBind: VModelDirective + vIf: Directive + VOnce: Directive + VSlot: Directive } } From 0cf01a5f8d67080ed8441ae8dbd27a0c50fb6ef4 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Fri, 16 Jul 2021 15:52:32 +0100 Subject: [PATCH 35/42] minor: fix test --- packages/runtime-core/src/h.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index a174d4439aa..f69291566ac 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -194,7 +194,7 @@ export function h, props?: RenderProps & Omit, E>, children?: RawChildren | RawSlots -): P +): VNode export function h(type: DefineComponent): VNode export function h(type: DefineComponent, children?: RawChildren): VNode @@ -203,7 +203,7 @@ export function h( type: Constructor

, props?: RenderProps, children?: RawChildren | RawSlots -): ExtractEmitEvents +): VNode export function h(type: Constructor, children?: RawChildren): VNode From 5573d90a057f03ba264df89b3a22e1258a05f4f9 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Sun, 15 Aug 2021 09:20:48 +0100 Subject: [PATCH 36/42] chore: remove bad import and fix compat render type --- packages/runtime-core/src/compat/global.ts | 9 ++++++--- packages/vue-compat/__tests__/instance.spec.ts | 11 +++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/runtime-core/src/compat/global.ts b/packages/runtime-core/src/compat/global.ts index 7f66e5dad59..15a4d9f7e0f 100644 --- a/packages/runtime-core/src/compat/global.ts +++ b/packages/runtime-core/src/compat/global.ts @@ -57,7 +57,7 @@ import { isCompatEnabled, softAssertCompatEnabled } from './compatConfig' -import { LegacyPublicInstance } from './instance' +import { LegacyPublicInstance, LegacyPublicProperties } from './instance' /** * @deprecated the default `Vue` export has been removed in Vue 3. The type for @@ -78,7 +78,7 @@ export type CompatVue = Pick & { nextTick: typeof nextTick use(plugin: Plugin, ...options: any[]): CompatVue - mixin(mixin: ComponentOptions): CompatVue + mixin(mixin: LegacyComponentOptions): CompatVue component(name: string): Component | undefined component(name: string, component: Component): CompatVue @@ -90,7 +90,7 @@ export type CompatVue = Pick & { /** * @deprecated */ - extend: (options?: ComponentOptions) => CompatVue + extend: (options?: LegacyComponentOptions) => CompatVue /** * @deprecated Vue 3 no longer needs set() for adding new properties. */ @@ -125,6 +125,9 @@ export type CompatVue = Pick & { super: CompatVue } +type LegacyComponentOptions = ComponentOptions & + ThisType + export let isCopyingConfig = false // exported only for test diff --git a/packages/vue-compat/__tests__/instance.spec.ts b/packages/vue-compat/__tests__/instance.spec.ts index 8b11b3d6c75..08029fb8b43 100644 --- a/packages/vue-compat/__tests__/instance.spec.ts +++ b/packages/vue-compat/__tests__/instance.spec.ts @@ -7,7 +7,6 @@ import { toggleDeprecationWarning } from '../../runtime-core/src/compat/compatConfig' import { LegacyPublicInstance } from '../../runtime-core/src/compat/instance' -import { defineComponent } from 'test-dts' beforeEach(() => { toggleDeprecationWarning(true) @@ -240,7 +239,8 @@ test('INSTANCE_LISTENERS', () => { components: { child: { template: `

`, - mounted() { + mounted(this: LegacyPublicInstance) { + // @ts-expect-error $listeners type: Record listeners = this.$listeners } } @@ -264,7 +264,7 @@ describe('INSTANCE_SCOPED_SLOTS', () => { components: { child: { compatConfig: { RENDER_FUNCTION: false }, - render() { + render(this: LegacyPublicInstance) { slots = this.$scopedSlots } } @@ -291,11 +291,14 @@ describe('INSTANCE_SCOPED_SLOTS', () => { components: { child: { compatConfig: { RENDER_FUNCTION: false }, - render() { + render(this: LegacyPublicInstance) { normalSlots = this.$slots scopedSlots = this.$scopedSlots } } + }, + render() { + this.$ } }).$mount() From a3408d7e0ab9da06ac6eec514321f956a4c2863d Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Sun, 15 Aug 2021 09:25:44 +0100 Subject: [PATCH 37/42] chore: remove type --- packages/runtime-core/src/compat/global.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/runtime-core/src/compat/global.ts b/packages/runtime-core/src/compat/global.ts index 15a4d9f7e0f..7f66e5dad59 100644 --- a/packages/runtime-core/src/compat/global.ts +++ b/packages/runtime-core/src/compat/global.ts @@ -57,7 +57,7 @@ import { isCompatEnabled, softAssertCompatEnabled } from './compatConfig' -import { LegacyPublicInstance, LegacyPublicProperties } from './instance' +import { LegacyPublicInstance } from './instance' /** * @deprecated the default `Vue` export has been removed in Vue 3. The type for @@ -78,7 +78,7 @@ export type CompatVue = Pick & { nextTick: typeof nextTick use(plugin: Plugin, ...options: any[]): CompatVue - mixin(mixin: LegacyComponentOptions): CompatVue + mixin(mixin: ComponentOptions): CompatVue component(name: string): Component | undefined component(name: string, component: Component): CompatVue @@ -90,7 +90,7 @@ export type CompatVue = Pick & { /** * @deprecated */ - extend: (options?: LegacyComponentOptions) => CompatVue + extend: (options?: ComponentOptions) => CompatVue /** * @deprecated Vue 3 no longer needs set() for adding new properties. */ @@ -125,9 +125,6 @@ export type CompatVue = Pick & { super: CompatVue } -type LegacyComponentOptions = ComponentOptions & - ThisType - export let isCopyingConfig = false // exported only for test From 75834779860573ebc5598a1f463a1a118497e911 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Sun, 15 Aug 2021 10:02:03 +0100 Subject: [PATCH 38/42] chore: improve test --- test-dts/component.test-d.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test-dts/component.test-d.ts b/test-dts/component.test-d.ts index 4afe888a242..8a20010dc7c 100644 --- a/test-dts/component.test-d.ts +++ b/test-dts/component.test-d.ts @@ -415,7 +415,13 @@ describe('functional', () => { const MyComponent: FunctionalComponent< { foo: number }, { ev: (a: string) => void } - > = (_, _2) => {} + > = (_, { emit }) => { + emit('ev', 'a') + // @ts-expect-error invalid argument + emit('ev', 12) + // @ts-expect-error invalid event + emit('o', '1') + } defineComponent(MyComponent) }) From 372eeb20bf2810af1cbc2226e6951122ceac9117 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Sat, 28 Aug 2021 11:45:32 +0100 Subject: [PATCH 39/42] wip: not properly working --- package.json | 2 +- .../runtime-core/src/apiDefineComponent.ts | 2 +- packages/runtime-core/src/componentEmits.ts | 18 +++++++++++ packages/runtime-core/src/componentOptions.ts | 31 ++++++++++++------- packages/runtime-core/src/componentProps.ts | 10 +++++- .../src/componentPublicInstance.ts | 24 +++++++++++--- .../runtime-core/src/helpers/typeUtils.ts | 4 ++- test-dts/defineComponent.test-d.tsx | 12 ++++++- yarn.lock | 7 ++++- 9 files changed, 88 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index ea8d44bb95f..bf91637abc0 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "semver": "^7.3.2", "serve": "^12.0.0", "ts-jest": "^26.2.0", - "typescript": "^4.2.2", + "typescript": "^4.4.2", "yorkie": "^2.0.0" } } diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 664f4d1acac..bfed9aa5543 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -226,7 +226,7 @@ export function defineComponent< LC extends Record = {}, Directives extends Record = {}, Exposed extends string = string, - Props = Readonly> & EmitsToProps, + Props = Readonly>, Defaults = ExtractDefaultPropTypes >( options: ComponentOptionsWithObjectProps< diff --git a/packages/runtime-core/src/componentEmits.ts b/packages/runtime-core/src/componentEmits.ts index 052805549b6..59553af2a76 100644 --- a/packages/runtime-core/src/componentEmits.ts +++ b/packages/runtime-core/src/componentEmits.ts @@ -53,6 +53,24 @@ export type EmitsToProps = T extends string[] } : {} +// declare function processEmits(a: T): EmitsToProps + +// const x = processEmits({ click: (a: 1) => true }) + +// declare const a: EmitsToProps<'click'[] & 'bar'[]> +// a.onClick + +// type Unpacked = T extends (infer U)[] +// ? U +// : T extends (...args: any[]) => infer U +// ? U +// : T extends Promise +// ? U +// : T +// type SSS = T extends string[] ? T : false + +// declare const t: SSS<'click'[] & 'bar'[]> + export type EmitVModelUpdate< T, E extends keyof T & string = keyof T & string diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 4932574dfbb..1532cba3ab5 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -70,6 +70,7 @@ import { } from './compat/compatConfig' import { OptionMergeFunction } from './apiCreateApp' import { Slots } from './componentSlots' +import { PublicProps } from './apiDefineComponent' /** * Interface for declaring custom options. @@ -99,7 +100,10 @@ type ExtractOptionProp = T extends ComponentOptionsBase< any, // M any, // Mixin any, // Extends - any // EmitsOptions + infer E, // EmitsOptions + any, + any, + any > ? unknown extends P ? {} @@ -252,7 +256,7 @@ export type ComponentOptionsWithoutProps< props?: undefined } & ThisType< CreateComponentPublicInstance< - PE, + Props, RawBindings, D, C, @@ -284,7 +288,7 @@ export type ComponentOptionsWithArrayProps< LC extends Record = {}, Directives extends Record = {}, Exposed extends string = string, - Props = Readonly<{ [key in PropNames]?: any }> & EmitsToProps + Props = Readonly<{ [key in PropNames]?: any }> > = ComponentOptionsBase< Props, RawBindings, @@ -336,7 +340,7 @@ export type ComponentOptionsWithObjectProps< LC extends Record = {}, Directives extends Record = {}, Exposed extends string = string, - Props = Readonly> & EmitsToProps, + Props = Readonly>, Defaults = ExtractDefaultPropTypes > = ComponentOptionsBase< Props, @@ -356,7 +360,7 @@ export type ComponentOptionsWithObjectProps< > & { props: PropsOptions & ThisType } & ThisType< - CreateComponentPublicInstance< + { supa: Props } & CreateComponentPublicInstance< Props, RawBindings, D, @@ -367,10 +371,11 @@ export type ComponentOptionsWithObjectProps< E, S, Props, - Defaults, + {}, false, LC, - Directives + Directives, + Exposed > > @@ -404,7 +409,7 @@ export type ComponentOptions< > & ThisType< CreateComponentPublicInstance< - {}, + Props, RawBindings, D, C, @@ -412,12 +417,13 @@ export type ComponentOptions< Mixin, Extends, E, - string, S, + Props, {}, false, LC, - Directives + Directives, + Exposed > > @@ -431,6 +437,7 @@ export type ComponentOptionsMixin = ComponentOptionsBase< any, any, any, + any, any > @@ -579,7 +586,7 @@ export type MergedComponentOptionsOverride = { errorCaptured?: MergedHook } -export type OptionTypesKeys = 'P' | 'B' | 'D' | 'C' | 'M' | 'Defaults' +export type OptionTypesKeys = 'P' | 'B' | 'D' | 'C' | 'M' | 'E' | 'Defaults' export type OptionTypesType< P = {}, @@ -587,6 +594,7 @@ export type OptionTypesType< D = {}, C extends ComputedOptions = {}, M extends MethodOptions = {}, + E extends EmitsOptions = {}, Defaults = {} > = { P: P @@ -594,6 +602,7 @@ export type OptionTypesType< D: D C: C M: M + E: E Defaults: Defaults } diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 66229117a63..319ff59935d 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -113,12 +113,20 @@ export type InferPropType = [T] extends [null] : V : T -export type ExtractPropTypes = O extends object +export type ExtractPropTypesOld = O extends object ? { [K in keyof O]?: unknown } & // This is needed to keep the relation between the option prop and the props, allowing to use ctrl+click to navigate to the prop options. see: #3656 { [K in RequiredKeys]: InferPropType } & { [K in OptionalKeys]?: InferPropType } : { [K in string]: any } +export type ExtractPropTypes> = O extends object + ? { + [K in keyof O]: K extends RK + ? InferPropType + : InferPropType | undefined + } + : {} // or { [K in string]: any } //TODO CR check + const enum BooleanFlags { shouldCast, shouldCastTrue diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 6d62c88f6eb..0c5ec1a6d01 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -36,7 +36,7 @@ import { shouldCacheAccess, MergedComponentOptionsOverride } from './componentOptions' -import { EmitsOptions, EmitFn } from './componentEmits' +import { EmitsOptions, EmitFn, EmitsToProps } from './componentEmits' import { Slots } from './componentSlots' import { markAttrsAccessed } from './componentRenderUtils' import { currentRenderingInstance } from './componentRenderContext' @@ -86,6 +86,7 @@ type MixinToOptionTypes = T extends ComponentOptionsBase< infer M, infer Mixin, infer Extends, + infer E, any, any, any, @@ -93,7 +94,7 @@ type MixinToOptionTypes = T extends ComponentOptionsBase< any, infer Defaults > - ? OptionTypesType

& + ? OptionTypesType

& IntersectionMixin & IntersectionMixin : never @@ -104,9 +105,13 @@ type ExtractMixin = { }[T extends ComponentOptionsMixin ? 'Mixin' : never] type IntersectionMixin = IsDefaultMixinComponent extends true - ? OptionTypesType<{}, {}, {}, {}, {}> + ? OptionTypesType<{}, {}, {}, {}, {}, {}, {}> : UnionToIntersection> +type UnionMixin = IsDefaultMixinComponent extends true + ? OptionTypesType<{}, {}, {}, {}, {}, {}, {}> + : ExtractMixin + type UnwrapMixinsType< T, Type extends OptionTypesKeys @@ -158,6 +163,11 @@ export type CreateComponentPublicInstance< EnsureNonVoid, PublicM extends MethodOptions = UnwrapMixinsType & EnsureNonVoid, + // Emits behave a bit different and require union instead of intersection + PublicE extends EmitsOptions = UnwrapMixinsType< + IntersectionMixin & IntersectionMixin, + 'E' + >, PublicDefaults = UnwrapMixinsType & EnsureNonVoid > = ComponentPublicInstance< @@ -222,11 +232,15 @@ export type ComponentPublicInstance< >, Exposed extends string = '' > = { + $HHH: E + $OOO: E extends (infer U)[] ? U[] : E + $ZZZ: EmitsToProps[] : E> $: ComponentInternalInstance $data: D - $props: MakeDefaultsOptional extends true + $props: (MakeDefaultsOptional extends true ? Partial & Omit

- : P & PublicProps + : P & PublicProps) & + EmitsToProps $attrs: Data $refs: Data $slots: Slots diff --git a/packages/runtime-core/src/helpers/typeUtils.ts b/packages/runtime-core/src/helpers/typeUtils.ts index 204543e6de2..8ab2862afd6 100644 --- a/packages/runtime-core/src/helpers/typeUtils.ts +++ b/packages/runtime-core/src/helpers/typeUtils.ts @@ -5,4 +5,6 @@ export type UnionToIntersection = ( : never // make keys required but keep undefined values -export type LooseRequired = { [P in string & keyof T]: T[P] } +// export type LooseRequired = { [P in string & keyof T]: T[P] } +// TODO validate this change, was what's above +export type LooseRequired = { [P in keyof T]: T[P] } diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index f384f8b1d40..21494750390 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -555,7 +555,7 @@ describe('with mixins', () => { return {} }, - setup(props) { + setup(props, _) { expectType(props.z) // props expectType<((...args: any[]) => any) | undefined>(props.onClick) @@ -713,6 +713,7 @@ describe('extends with mixins', () => { } }, data() { + this.$props.onBar return { a: 1 } @@ -755,6 +756,15 @@ describe('extends with mixins', () => { }, render() { const props = this.$props + + this.$HHH + this.$ZZZ + this.supa + + this.$emit('bar', 2) + this.$emit('foo', 2) + this.$emit('') + // props expectType<((...args: any[]) => any) | undefined>(props.onClick) // from Mixin diff --git a/yarn.lock b/yarn.lock index 53dc72e8960..1dde7ff3c86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7242,7 +7242,12 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.2.2, typescript@~4.3.5: +typescript@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.2.tgz#6d618640d430e3569a1dfb44f7d7e600ced3ee86" + integrity sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ== + +typescript@~4.3.5: version "4.3.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== From 847d67d5cecffeeb9d0c32e86f174727b749e59f Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Sat, 28 Aug 2021 16:23:22 +0100 Subject: [PATCH 40/42] wip: improve mixin emits --- .../runtime-core/src/apiDefineComponent.ts | 16 ++++--- packages/runtime-core/src/componentOptions.ts | 32 +++++++------- .../src/componentPublicInstance.ts | 24 +++++++---- test-dts/defineComponent.test-d.tsx | 42 +++++++++++++++---- 4 files changed, 76 insertions(+), 38 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index bfed9aa5543..0d315b25fac 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -35,6 +35,10 @@ export type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps +type FixS = T extends string[] + ? Record + : T + export type DefineComponent< PropsOrPropOptions = {}, RawBindings = {}, @@ -43,14 +47,14 @@ export type DefineComponent< M extends MethodOptions = MethodOptions, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - E extends EmitsOptions = Record, + E extends EmitsOptions = {}, EE extends string = string, S = any, LC extends Record = {}, Directives extends Record = {}, Exposed extends string = string, PP = PublicProps, - Props = Readonly> & EmitsToProps, + Props = Readonly>, Defaults = ExtractDefaultPropTypes > = ComponentPublicInstanceConstructor< CreateComponentPublicInstance< @@ -61,7 +65,7 @@ export type DefineComponent< M, Mixin, Extends, - E, + FixS, S, PP & Props, Defaults, @@ -70,7 +74,7 @@ export type DefineComponent< Directives & GlobalDirectives, Exposed > & - Props + Readonly> > & /** * just typescript */ { __isDefineComponent?: true } & ComponentOptionsBase< @@ -170,7 +174,7 @@ export function defineComponent< M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - E extends EmitsOptions = Record, + E extends EmitsOptions = {}, EE extends string = string, S = any, LC extends Record = {}, @@ -220,7 +224,7 @@ export function defineComponent< M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - E extends EmitsOptions = Record, + E extends EmitsOptions = {}, EE extends string = string, S = any, LC extends Record = {}, diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 1532cba3ab5..0055c7ca08b 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -100,14 +100,11 @@ type ExtractOptionProp = T extends ComponentOptionsBase< any, // M any, // Mixin any, // Extends - infer E, // EmitsOptions - any, - any, - any + infer E // EmitsOptions > ? unknown extends P ? {} - : P + : P & EmitsToProps : {} export interface ComponentOptionsBase< @@ -118,14 +115,14 @@ export interface ComponentOptionsBase< M extends MethodOptions, Mixin extends ComponentOptionsMixin, Extends extends ComponentOptionsMixin, - E extends EmitsOptions, + E extends EmitsOptions = {}, EE extends string = string, S = any, LC extends Record = {}, Directives extends Record = {}, Exposed extends string = string, Defaults = {} -> extends LegacyOptions, +> extends LegacyOptions, ComponentInternalOptions, ComponentCustomOptions { setup?: ( @@ -134,7 +131,8 @@ export interface ComponentOptionsBase< LooseRequired< Props & UnionToIntersection> & - UnionToIntersection> + UnionToIntersection> & + EmitsToProps > >, ctx: SetupContext> @@ -150,7 +148,7 @@ export interface ComponentOptionsBase< components?: LC directives?: Directives inheritAttrs?: boolean - emits?: (E | EE[]) & ThisType + emits?: (E & ThisType) | EE[] expose?: Exposed[] serverPrefetch?(): Promise @@ -334,7 +332,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, S = any, LC extends Record = {}, @@ -360,7 +358,7 @@ export type ComponentOptionsWithObjectProps< > & { props: PropsOptions & ThisType } & ThisType< - { supa: Props } & CreateComponentPublicInstance< + CreateComponentPublicInstance< Props, RawBindings, D, @@ -438,6 +436,9 @@ export type ComponentOptionsMixin = ComponentOptionsBase< any, any, any, + any, + any, + any, any > @@ -481,7 +482,8 @@ interface LegacyOptions< C extends ComputedOptions, M extends MethodOptions, Mixin extends ComponentOptionsMixin, - Extends extends ComponentOptionsMixin + Extends extends ComponentOptionsMixin, + E extends EmitsOptions > { compatConfig?: CompatConfig @@ -500,7 +502,8 @@ interface LegacyOptions< {}, MethodOptions, Mixin, - Extends + Extends, + E >, vm: CreateComponentPublicInstance< Props, @@ -509,7 +512,8 @@ interface LegacyOptions< {}, MethodOptions, Mixin, - Extends + Extends, + E > ) => D computed?: C diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 0c5ec1a6d01..e6f0b7b7b44 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -44,6 +44,7 @@ import { warn } from './warning' import { UnionToIntersection } from './helpers/typeUtils' import { Directive } from './directives' import { installCompatInstanceProperties } from './compat/instance' +import { ObjectEmitsOptions } from 'test-dts' /** * Custom properties added to component instances in any way and can be accessed through `this` @@ -139,6 +140,12 @@ export type ComponentPublicInstanceConstructor< new (...args: any[]): T } +type FixS = T extends string[] + ? // the omit serves to remove the type 'bar[]' from `bar[] & { foo: Function}` + Record & + (T extends object ? Omit : never) + : T + export type CreateComponentPublicInstance< P = {}, B = {}, @@ -156,7 +163,7 @@ export type CreateComponentPublicInstance< Directives extends Record = {}, Exposed extends string = string, PublicMixin = IntersectionMixin & IntersectionMixin, - PublicP = UnwrapMixinsType & EnsureNonVoid

, + PublicP = Readonly> & EnsureNonVoid

, PublicB = UnwrapMixinsType & EnsureNonVoid, PublicD = UnwrapMixinsType & EnsureNonVoid, PublicC extends ComputedOptions = UnwrapMixinsType & @@ -164,10 +171,11 @@ export type CreateComponentPublicInstance< PublicM extends MethodOptions = UnwrapMixinsType & EnsureNonVoid, // Emits behave a bit different and require union instead of intersection - PublicE extends EmitsOptions = UnwrapMixinsType< - IntersectionMixin & IntersectionMixin, - 'E' - >, + PublicE extends EmitsOptions = FixS< + UnwrapMixinsType, 'E'> + > & + FixS, 'E'>> & + FixS>, PublicDefaults = UnwrapMixinsType & EnsureNonVoid > = ComponentPublicInstance< @@ -176,7 +184,7 @@ export type CreateComponentPublicInstance< PublicD, PublicC, PublicM, - E, + PublicE, S, PublicProps, PublicDefaults, @@ -232,9 +240,7 @@ export type ComponentPublicInstance< >, Exposed extends string = '' > = { - $HHH: E - $OOO: E extends (infer U)[] ? U[] : E - $ZZZ: EmitsToProps[] : E> + $XXX: E $: ComponentInternalInstance $data: D $props: (MakeDefaultsOptional extends true diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index 21494750390..7de755b18eb 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -701,6 +701,8 @@ describe('with extends', () => { describe('extends with mixins', () => { const Mixin = defineComponent({ emits: ['bar'], + // emits: { bar: (a: string) => true }, + props: { mP1: { type: String, @@ -739,14 +741,31 @@ describe('extends with mixins', () => { }, computed: { c(): number { + this.$XXX return this.p2 + this.b } } }) + const OtherMixin = defineComponent({ + emits: { + test: (a: boolean) => true + }, + + render() { + this.$emit('test', true) + + // @ts-expect-error + this.$emit('test', 0) + + // @ts-expect-error + this.$emit('') + } + }) + const MyComponent = defineComponent({ extends: Base, - mixins: [Mixin], - emits: ['click'], + mixins: [Mixin, OtherMixin], + emits: ['click', 'lock'], props: { // required should make property non-void z: { @@ -757,14 +776,18 @@ describe('extends with mixins', () => { render() { const props = this.$props - this.$HHH - this.$ZZZ - this.supa - - this.$emit('bar', 2) - this.$emit('foo', 2) + //@ts-expect-error this.$emit('') + this.$emit('bar') + this.$emit('foo') + this.$emit('click') + + this.$emit('test', true) + + //@ts-expect-error + this.$emit('test', 0) + // props expectType<((...args: any[]) => any) | undefined>(props.onClick) // from Mixin @@ -1068,7 +1091,8 @@ describe('extract instance type', () => { required: true }, c: Number - } + }, + setup(props) {} }) const compA = {} as InstanceType From 1c4ddad05e7110b163b15b5019e96331436c4263 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Sun, 29 Aug 2021 13:28:23 +0100 Subject: [PATCH 41/42] chore: duplicated must Component types --- .../runtime-core/src/apiDefineComponent.ts | 368 ++++++++++++++++- packages/runtime-core/src/component.ts | 42 +- packages/runtime-core/src/componentOptions.ts | 376 +++++++++++++++++- .../src/componentPublicInstance.ts | 226 ++++++++++- packages/runtime-core/src/componentSlots.ts | 14 +- packages/runtime-core/src/h.ts | 104 ++++- test-dts/tsx.test-d.tsx | 1 + 7 files changed, 1113 insertions(+), 18 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 0d315b25fac..cd4c363982d 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -6,7 +6,12 @@ import { ComponentOptionsWithObjectProps, ComponentOptionsMixin, RenderFunction, - ComponentOptionsBase + ComponentOptionsBase, + BettterComponentOptionsWithObjectProps, + BetterComponentOptions, + BetterComponentOptionsAny, + BettterComponentOptionsWithArrayProps, + BettterComponentOptionsWithoutProps } from './componentOptions' import { SetupContext, @@ -14,7 +19,8 @@ import { ComponentCustomProps, Component, GlobalDirectives, - GlobalComponents + GlobalComponents, + BetterComponent } from './component' import { ExtractPropTypes, @@ -26,10 +32,12 @@ import { isFunction } from '@vue/shared' import { VNodeProps } from './vnode' import { CreateComponentPublicInstance, - ComponentPublicInstanceConstructor + ComponentPublicInstanceConstructor, + RenderComponent } from './componentPublicInstance' import { Slots } from './componentSlots' import { Directive } from './directives' +import { ComponentObjectPropsOptions, PropType } from 'test-dts' export type PublicProps = VNodeProps & AllowedComponentProps & @@ -272,3 +280,357 @@ export function defineComponent< export function defineComponent(options: unknown) { return isFunction(options) ? { setup: options, name: options.name } : options } + +// Type Helper for defineComponent return +export type BetterDefineComponent< + Props extends Record, + Emits extends EmitsOptions = {}, + S = {}, + LC extends Record = {}, + LD extends Record = {}, + RawBindings = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + Exposed extends string = string, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + Defaults = {}, + Options = any +> = BetterComponent< + Props, + Emits, + S, + // TODO ADD Similar binding as the BetterCreateComponentPublicInstance + {}, + LC, + LD, + D, + RawBindings, + C, + M, + Exposed, + Mixin, + Extends, + Options +> & + RenderComponent + +// defineComponent is a utility that is primarily used for type inference +// when declaring components. Type inference is provided in the component +// options (provided as the argument). The returned value has artificial types +// for TSX / manual render function / IDE support. + +// overload 1: direct setup function +// (uses user defined props interface) +export function betterDefineComponent< + Props extends Record = {}, + RawBindings = {}, + Emits extends EmitsOptions = {}, + S = {}, + Exposed extends string = string +>( + setup: ( + props: Readonly, + ctx: SetupContext> + ) => RawBindings | RenderFunction +): { OOO: number } & BetterDefineComponent< + Props, + Emits, + S, + {}, + {}, + RawBindings, + {}, + {}, + {}, + Exposed, + {}, + {}, + {}, + BetterComponentOptions< + Props, + Emits, + S, + {}, + {}, + RawBindings, + {}, + {}, + {}, + string, + Exposed + > +> + +// overload 2: object format with no props +// (uses user defined props interface) +// return type is for Vetur and TSX support +export function betterDefineComponent< + Emits extends EmitsOptions = {}, + S = {}, + LC extends Record = {}, + LD extends Record = {}, + RawBindings = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + EE extends string = string, + Exposed extends string = string, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + Defaults = {} +>( + options: BettterComponentOptionsWithoutProps< + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + EE, + Exposed, + Mixin, + Extends, + Defaults + > +): BetterDefineComponent< + {}, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + Exposed, + Mixin, + Extends, + Defaults, + BettterComponentOptionsWithoutProps< + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + EE, + Exposed, + Mixin, + Extends, + Defaults + > +> +// 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 betterDefineComponent< + PropNames extends string, + Emits extends EmitsOptions = {}, + S = {}, + LC extends Record = {}, + LD extends Record = {}, + RawBindings = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + EE extends string = string, + Exposed extends string = string, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + Defaults = {}, + Props extends Record = Readonly<{ [key in PropNames]?: any }> +>( + options: BettterComponentOptionsWithArrayProps< + Props, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + EE, + Exposed, + Mixin, + Extends, + Defaults, + PropNames + > +): BetterDefineComponent< + Props, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + Exposed, + Mixin, + Extends, + Defaults, + BettterComponentOptionsWithArrayProps< + Props, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + EE, + Exposed, + Mixin, + Extends, + Defaults, + PropNames + > +> + +// overload 4: object format with object props declaration +// see `ExtractPropTypes` in ./componentProps.ts +export function betterDefineComponent< + PropsOptions extends ComponentObjectPropsOptions = ComponentObjectPropsOptions, + Emits extends EmitsOptions = {}, + S = {}, + LC extends Record = {}, + LD extends Record = {}, + RawBindings = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + EE extends string = string, + Exposed extends string = string, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + Defaults = ExtractDefaultPropTypes, + Props extends Record = Readonly< + ExtractPropTypes + > +>( + options: BettterComponentOptionsWithObjectProps< + Props, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + EE, + Exposed, + Mixin, + Extends, + Defaults, + PropsOptions + > +): BetterDefineComponent< + Props, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + Exposed, + Mixin, + Extends, + Defaults, + BettterComponentOptionsWithObjectProps< + Props, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + EE, + Exposed, + Mixin, + Extends, + Defaults, + PropsOptions + > +> + +// implementation, close to no-op +export function betterDefineComponent(options: unknown) { + return isFunction(options) ? { setup: options, name: options.name } : options +} + +const xxx = betterDefineComponent({ + props: ['test'] +}) + +declare function test< + T extends BetterDefineComponent< + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any + > +>( + t: T +): T extends BetterComponent< + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + infer O +> + ? O + : { nope: true } + +const r = test( + betterDefineComponent({ + // props: ['ttet'] + }) +) + +const rrr = betterDefineComponent({ + props: { + test: Number + } +}) + +const rt = betterDefineComponent<{ test: number }>({ + setup() { + return { + a: 2 + } + } +}) +rt.OOO diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index f01266583c4..952cf6221d6 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -23,7 +23,8 @@ import { ComponentPropsOptions, NormalizedPropsOptions, initProps, - normalizePropsOptions + normalizePropsOptions, + Prop } from './componentProps' import { Slots, initSlots, InternalSlots } from './componentSlots' import { warn } from './warning' @@ -32,6 +33,8 @@ import { AppContext, createAppContext, AppConfig } from './apiCreateApp' import { Directive, validateDirectiveName } from './directives' import { applyOptions, + BetterComponentOptions, + BetterComponentOptionsMixin, ComponentOptions, ComponentOptionsMixin, ComputedOptions, @@ -189,6 +192,43 @@ export type Component< | ConcreteComponent | ComponentPublicInstanceConstructor +// export type BetterConcreteComponent< +// Props extends Record> = {}, +// Emits extends EmitsOptions = {}, +// Slots = {}, +// // Allows to expose public API properties, this bypasses Data/Computed/Methods, +// // easier to declare manually +// Bindings extends Record = {}, +// Options extends ComponentOptions = {} + +// > =; + +export type BetterComponent< + Props extends Record = {}, + Emits extends EmitsOptions = {}, + Slots = {}, + // Allows to expose public API properties, this bypasses Data/Computed/Methods, + // easier to declare manually + Bindings extends Record = {}, + LocalComponents extends Record = {}, + LocalDirectives extends Record = {}, + D = any, + RawBindings = any, + C extends ComputedOptions = ComputedOptions, + M extends MethodOptions = MethodOptions, + Exposed extends string = string, + Mixin extends BetterComponentOptionsMixin = any, + Extends extends BetterComponentOptionsMixin = any, + Options extends BetterComponentOptions = any +> = + | ConcreteComponent + | ComponentPublicInstanceConstructor + | { supa: Options } + +const ddd: BetterComponent = { + setup() {} +} + export { ComponentOptions } type LifecycleHook = TFn[] | null diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 0055c7ca08b..e9898e83a2c 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -55,7 +55,8 @@ import { EmitsOptions, EmitsToProps } from './componentEmits' import { Directive } from './directives' import { CreateComponentPublicInstance, - ComponentPublicInstance + ComponentPublicInstance, + BetterCreateComponentPublicInstance } from './componentPublicInstance' import { warn } from './warning' import { VNodeChild } from './vnode' @@ -107,6 +108,110 @@ type ExtractOptionProp = T extends ComponentOptionsBase< : P & EmitsToProps : {} +export interface BetterComponentOptionsBase< + Props extends Record, + Emits extends EmitsOptions, + S, + LC extends Record, + LD extends Record, + RawBindings, + D, + C extends ComputedOptions, + M extends MethodOptions, + EE extends string = string, + Exposed extends string = string, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + Defaults = {} +> extends LegacyOptions, + ComponentInternalOptions, + ComponentCustomOptions { + setup?: ( + this: void, + props: Readonly< + LooseRequired< + Props & + UnionToIntersection> & + UnionToIntersection> & + EmitsToProps + > + >, + ctx: SetupContext> + ) => Promise | RawBindings | RenderFunction | void + + name?: string + template?: string | object // can be a direct DOM node + // Note: we are intentionally using the signature-less `Function` type here + // since any type with signature will cause the whole inference to fail when + // the return expression contains reference to `this`. + // Luckily `render()` doesn't need any arguments nor does it care about return + // type. + render?: Function + components?: LC + directives?: LD + inheritAttrs?: boolean + emits?: (Emits & ThisType) | EE[] + expose?: Exposed[] + serverPrefetch?(): Promise + + // Runtime compiler only ----------------------------------------------------- + compilerOptions?: RuntimeCompilerOptions + + slots?: S & ThisType + + // Internal ------------------------------------------------------------------ + + /** + * SSR only. This is produced by compiler-ssr and attached in compiler-sfc + * not user facing, so the typing is lax and for test only. + * @internal + */ + ssrRender?: ( + ctx: any, + push: (item: any) => void, + parentInstance: ComponentInternalInstance, + attrs: Data | undefined, + // for compiler-optimized bindings + $props: ComponentInternalInstance['props'], + $setup: ComponentInternalInstance['setupState'], + $data: ComponentInternalInstance['data'], + $options: ComponentInternalInstance['ctx'] + ) => void + + /** + * Only generated by compiler-sfc to mark a ssr render function inlined and + * returned from setup() + * @internal + */ + __ssrInlineRender?: boolean + + /** + * marker for AsyncComponentWrapper + * @internal + */ + __asyncLoader?: () => Promise + /** + * the inner component resolved by the AsyncComponentWrapper + * @internal + */ + __asyncResolved?: ConcreteComponent + + // Type differentiators ------------------------------------------------------ + + // Note these are internal but need to be exposed in d.ts for type inference + // to work! + + // type-only differentiator to separate OptionWithoutProps from a constructor + // type returned by defineComponent() or FunctionalComponent + call?: (this: unknown, ...args: unknown[]) => never + // type-only differentiators for built-in Vnode types + __isFragment?: never + __isTeleport?: never + __isSuspense?: never + + __defaults?: Defaults +} + export interface ComponentOptionsBase< Props, RawBindings, @@ -425,6 +530,209 @@ export type ComponentOptions< > > +export type BettterComponentOptionsWithoutProps< + Emits extends EmitsOptions = {}, + S = {}, + LC extends Record = {}, + LD extends Record = {}, + RawBindings = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + EE extends string = string, + Exposed extends string = string, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + Defaults = {} +> = BetterComponentOptions< + {}, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + EE, + Exposed, + Mixin, + Extends, + Defaults +> & { + props?: null +} + +export type BettterComponentOptionsWithArrayProps< + Props extends Record = {}, + Emits extends EmitsOptions = {}, + S = {}, + LC extends Record = {}, + LD extends Record = {}, + RawBindings = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + EE extends string = string, + Exposed extends string = string, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + Defaults = {}, + PropNames extends string = string +> = BetterComponentOptions< + Props, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + EE, + Exposed, + Mixin, + Extends, + Defaults +> & { + props: PropNames[] +} + +export type BettterComponentOptionsWithObjectProps< + Props extends Record = {}, + Emits extends EmitsOptions = {}, + S = {}, + LC extends Record = {}, + LD extends Record = {}, + RawBindings = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + EE extends string = string, + Exposed extends string = string, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + Defaults = {}, + PropsOptions extends ComponentObjectPropsOptions = ComponentObjectPropsOptions +> = BetterComponentOptions< + Props, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + EE, + Exposed, + Mixin, + Extends, + Defaults +> & { + props: PropsOptions & ThisType +} + +// export type BetterComponentOptionsTyped< +// Props extends Record = {}, +// Emits extends EmitsOptions = {}, +// S = {}, +// LC extends Record = {}, +// LD extends Record = {}, +// RawBindings = {}, +// D = {}, +// C extends ComputedOptions = {}, +// M extends MethodOptions = {}, +// EE extends string = string, +// Exposed extends string = string, +// Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, +// Extends extends ComponentOptionsMixin = ComponentOptionsMixin, +// Defaults = {} +// > = BetterComponentOptionsBase< +// Props, +// Emits, +// S, +// LC, +// LD, +// RawBindings, +// D, +// C, +// M, +// EE, +// Exposed, +// Mixin, +// Extends, +// Defaults +// > & +// ThisType< +// BetterCreateComponentPublicInstance< +// Props, +// Emits, +// S, +// LC, +// LD, +// RawBindings, +// D, +// C, +// M, +// Exposed, +// Mixin, +// Extends, +// PublicProps, +// Defaults +// > +// > + +export type BetterComponentOptions< + Props extends Record = {}, + Emits extends EmitsOptions = {}, + S = {}, + LC extends Record = {}, + LD extends Record = {}, + RawBindings = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + EE extends string = string, + Exposed extends string = string, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + Defaults = {} +> = BetterComponentOptionsBase< + Props, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + EE, + Exposed, + Mixin, + Extends, + Defaults +> & + ThisType< + BetterCreateComponentPublicInstance< + Props, + Emits, + S, + LC, + LD, + RawBindings, + D, + C, + M, + Exposed, + Mixin, + Extends, + PublicProps, + Defaults + > + > + export type ComponentOptionsMixin = ComponentOptionsBase< any, any, @@ -442,6 +750,35 @@ export type ComponentOptionsMixin = ComponentOptionsBase< any > +export type BetterComponentOptionsAny = BetterComponentOptions< + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any +> + +export type BetterComponentOptionsMixin = BetterComponentOptionsBase< + any, + any, + any, + any, + any, + any, + any, + any, + any +> + export type ComputedOptions = Record< string, ComputedGetter | WritableComputedOptions @@ -481,9 +818,9 @@ interface LegacyOptions< D, C extends ComputedOptions, M extends MethodOptions, + E extends EmitsOptions, Mixin extends ComponentOptionsMixin, - Extends extends ComponentOptionsMixin, - E extends EmitsOptions + Extends extends ComponentOptionsMixin > { compatConfig?: CompatConfig @@ -610,6 +947,39 @@ export type OptionTypesType< Defaults: Defaults } +export type BetterOptionTypesKeys = + | 'P' + | 'E' + | 'LC' + | 'LD' + | 'B' + | 'D' + | 'C' + | 'M' + | 'Defaults' + +export type BetterOptionTypesType< + P extends Record = {}, + E extends EmitsOptions = {}, + LC extends Record = {}, + LD extends Record = {}, + B = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + Defaults = {} +> = { + P: P + E: E + LC: LC + LD: LD + B: B + D: D + C: C + M: M + Defaults: Defaults +} + const enum OptionTypes { PROPS = 'Props', DATA = 'Data', diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index e6f0b7b7b44..befecf9f295 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -34,17 +34,22 @@ import { OptionTypesKeys, resolveMergedOptions, shouldCacheAccess, - MergedComponentOptionsOverride + MergedComponentOptionsOverride, + BetterOptionTypesType, + BetterComponentOptionsBase, + BetterOptionTypesKeys, + BetterComponentOptionsMixin, + BetterComponentOptionsAny } from './componentOptions' import { EmitsOptions, EmitFn, EmitsToProps } from './componentEmits' -import { Slots } from './componentSlots' +import { RenderSlot, Slots } from './componentSlots' import { markAttrsAccessed } from './componentRenderUtils' import { currentRenderingInstance } from './componentRenderContext' import { warn } from './warning' import { UnionToIntersection } from './helpers/typeUtils' import { Directive } from './directives' import { installCompatInstanceProperties } from './compat/instance' -import { ObjectEmitsOptions } from 'test-dts' +import { Slot } from './componentSlots' /** * Custom properties added to component instances in any way and can be accessed through `this` @@ -100,6 +105,37 @@ type MixinToOptionTypes = T extends ComponentOptionsBase< IntersectionMixin : never +type BetterMixinToOptionTypes = T extends BetterComponentOptionsBase< + infer Props, + infer Emits, + any, + infer LC, + infer LD, + infer B, + infer D, + infer C, + infer M, + any, + any, + infer Mixin, + infer Extends, + infer Defaults +> + ? BetterOptionTypesType< + Props & {}, + Emits /* & {}*/, + LC & {}, + LD & {}, + B & {}, + D & {}, + C & {}, + M & {}, + Defaults & {} + > & + BetterIntersectionMixin & + BetterIntersectionMixin + : never + // ExtractMixin(map type) is used to resolve circularly references type ExtractMixin = { Mixin: MixinToOptionTypes @@ -109,9 +145,17 @@ type IntersectionMixin = IsDefaultMixinComponent extends true ? OptionTypesType<{}, {}, {}, {}, {}, {}, {}> : UnionToIntersection> -type UnionMixin = IsDefaultMixinComponent extends true - ? OptionTypesType<{}, {}, {}, {}, {}, {}, {}> - : ExtractMixin +type BetterExtractMixin = { + Mixin: MixinToOptionTypes +}[T extends ComponentOptionsMixin ? 'Mixin' : never] +type BetterIntersectionMixin = IsDefaultMixinComponent extends true + ? BetterOptionTypesType<{}, {}, {}, {}, {}, {}, {}> + : BetterExtractMixin + +type BetterUnwrapMixinsType< + T, + Type extends BetterOptionTypesKeys +> = T extends BetterOptionTypesType ? T[Type] : never type UnwrapMixinsType< T, @@ -120,6 +164,67 @@ type UnwrapMixinsType< type EnsureNonVoid = T extends void ? {} : T +/** + Props extends Record = {}, + Emits extends EmitsOptions = {}, + S extends Slots = {}, + Bindings extends Record = {}, + LC extends Record = {}, + LD extends Record = {}, + D = {}, // return from data() + Options extends BetterComponentOptionsAny = BetterComponentOptionsBase< + Props, + Emits, + S, + LC, + LD, + any, + D, + any, + any + > + +*/ + +// Render component AKA ComponentPublicInstanceConstructor +// NOTE maybe this can be a class? to allow more advanced typing +export type RenderComponent< + Props extends Record = {}, + Emits extends EmitsOptions = {}, + S = {}, + // Allows to expose public API properties, this bypasses Data/Computed/Methods, + // easier to declare manually + Bindings extends Record = {}, + LC extends Record = {}, + LD extends Record = {}, + D = {}, // return from data() + Options extends BetterComponentOptionsAny = BetterComponentOptionsBase< + Props, + Emits, + S, + LC, + LD, + any, + D, + any, + any + > +> = { + __isFragment?: never + __isTeleport?: never + __isSuspense?: never + new (...args: any[]): BetterComponentPublicInstance< + Props, + Emits, + Readonly>, + Bindings, + LC, + LD, + D, + Options + > +} + export type ComponentPublicInstanceConstructor< T extends ComponentPublicInstance< Props, @@ -146,6 +251,72 @@ type FixS = T extends string[] (T extends object ? Omit : never) : T +export type BetterCreateComponentPublicInstance< + P extends Record = {}, + E extends EmitsOptions = {}, + S = any, + LC extends Record = {}, + LD extends Record = {}, + B = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + Exposed extends string = string, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + PublicProps = P, + Defaults = {}, + MakeDefaultsOptional extends boolean = false, + PublicMixin = BetterIntersectionMixin & + BetterIntersectionMixin, + PublicP extends Record = Readonly< + BetterUnwrapMixinsType + > & + EnsureNonVoid

, + PublicLC extends Record = BetterUnwrapMixinsType< + PublicMixin, + 'LC' + > & + EnsureNonVoid, + PublicLD extends Record = BetterUnwrapMixinsType< + PublicMixin, + 'LD' + > & + EnsureNonVoid, + PublicB = BetterUnwrapMixinsType & EnsureNonVoid, + PublicD = BetterUnwrapMixinsType & EnsureNonVoid, + PublicC extends ComputedOptions = BetterUnwrapMixinsType & + EnsureNonVoid, + PublicM extends MethodOptions = BetterUnwrapMixinsType & + EnsureNonVoid, + // Emits behave a bit different and require union instead of intersection + PublicE extends EmitsOptions = FixS< + BetterUnwrapMixinsType, 'E'> + > & + FixS, 'E'>> & + FixS>, + PublicDefaults = BetterUnwrapMixinsType & + EnsureNonVoid +> = BetterComponentPublicInstance< + (MakeDefaultsOptional extends true + ? Partial & + Omit + : PublicP & PublicProps) & + EmitsToProps, + PublicE, + Readonly>, + ExposedKeys< + ShallowUnwrapRef & + UnwrapNestedRefs & + ExtractComputedReturns & + PublicM, + Exposed + >, + PublicLC, + PublicLD, + PublicD +> + export type CreateComponentPublicInstance< P = {}, B = {}, @@ -213,6 +384,49 @@ export type ExposedKeys< Exposed extends string & keyof T > = '' extends Exposed ? T : Pick +export type BetterComponentPublicInstance< + Props extends Record = {}, + Emits extends EmitsOptions = {}, + S extends Slots = {}, + Bindings extends Record = {}, + LC extends Record = {}, + LD extends Record = {}, + D = {}, // return from data() + Options extends BetterComponentOptionsAny = BetterComponentOptionsBase< + Props, + Emits, + S, + LC, + LD, + any, + D, + any, + any + > +> = { + $: ComponentInternalInstance + $data: D + $props: Props + + $attrs: Data + $refs: Data + $slots: Readonly + $root: BetterComponentPublicInstance | null + $parent: BetterComponentPublicInstance | null + $emit: EmitFn + $el: any + $options: Options & MergedComponentOptionsOverride + $forceUpdate: () => void + $nextTick: typeof nextTick + $watch( + source: string | Function, + cb: Function, + options?: WatchOptions + ): WatchStopHandle +} & Bindings & + // TODO check if the custom properties are exposed with expose + ComponentCustomProperties + // 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/componentSlots.ts b/packages/runtime-core/src/componentSlots.ts index c1b51fe67f4..542bb0a524e 100644 --- a/packages/runtime-core/src/componentSlots.ts +++ b/packages/runtime-core/src/componentSlots.ts @@ -22,9 +22,11 @@ import { isHmrUpdating } from './hmr' import { DeprecationTypes, isCompatEnabled } from './compat/compatConfig' import { toRaw } from '@vue/reactivity' -export type Slot = (...args: any[]) => VNode[] +export type Slot = (...args: any[]) => VNode[] | VNode -export type SlotTyped = T extends null ? () => VNode[] : (arg: T) => VNode[] +export type SlotTyped = T extends null + ? () => VNode[] | VNode + : (arg: T) => VNode[] | VNode export type InternalSlots = { [K in keyof T]?: T[K] extends () => infer R ? SlotTyped : SlotTyped @@ -42,6 +44,14 @@ export type Slots = RenderSlot & ? Readonly> : Readonly>) +declare const rr: Slots<{ a: null }> extends Readonly> + ? true + : false + +if (rr) { + rr?.valueOf() +} + export type RenderSlot = { // manual render fn hint to skip forced children updates $stable?: boolean diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index b54d783c814..39ba57d5cc3 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -16,11 +16,14 @@ import { FunctionalComponent, Component, ConcreteComponent, - ComponentOptions + ComponentOptions, + BetterComponent } from './component' import { EmitsOptions } from './componentEmits' -import { DefineComponent } from './apiDefineComponent' -import { Slots } from 'test-dts' +import { betterDefineComponent, DefineComponent } from './apiDefineComponent' +import { Prop, Slots } from 'test-dts' +import { BetterComponentOptions } from './componentOptions' +import { RenderComponent } from './componentPublicInstance' // `h` is a more user-friendly version of `createVNode` that allows omitting the // props when possible. It is intended for manually written render functions. @@ -92,6 +95,7 @@ type ExtractEmitEvents = T extends Readonly> : (...args: any[]) => void } +// TODO remove `on*` props aka Emit events type ExtractEmitPropUpdate< P = {}, PK extends keyof P & string = keyof P & string @@ -109,6 +113,11 @@ type RenderProps = | (Partial> & RawProps & P & ExtractEmitPropUpdate

) | ({} extends P ? Partial> | null : never) +type RenderSlots = + | Slots + | ({} extends S ? RawSlots : Slots) + | RawChildren + // The following is a series of overloads for providing props validation of // manually written render functions. @@ -273,3 +282,92 @@ export function h(type: any, propsOrChildren?: any, children?: any): VNode { return createVNode(type, propsOrChildren, children) } } + +// declare function betterH< +// P extends Record, +// E extends EmitsOptions, +// S +// >( +// type: BetterComponentOptions, +// props?: RenderProps, +// children?: (RawChildren & Slots) | ({} extends S ? RawSlots : Slots) +// ): P +export function betterH< + P extends Record, + E extends EmitsOptions, + S +>( + type: BetterComponent, + props?: RenderProps, + children?: RenderSlots +): P + +export function betterH< + P extends Record, + E extends EmitsOptions, + S +>( + type: RenderComponent, + props?: RenderProps, + children?: RenderSlots +): P +export function betterH( + type: any, + propsOrChildren?: any, + children?: any +): any {} + +declare const MyComp: BetterComponent< + { test: number }, + ['hey'], + { + default: null + typedSlot: { a: number } + } +> +const r = betterH( + MyComp, + { + test: 2 + }, + { + default() { + return {} as unknown as VNode + }, + typedSlot(e) { + return {} as unknown as VNode + } + } +) + +const x = betterH( + {} as unknown as RenderComponent< + { + test: number + }, + ['tst'], + { + default: null + } + >, + { + test: 2 + } +) + +const Comp = betterDefineComponent({ + props: { + test: Number + } +}) + +betterH( + Comp, + { + test: 1 + }, + {} +) + +declare function test(t: BetterComponent): boolean +test(Comp) diff --git a/test-dts/tsx.test-d.tsx b/test-dts/tsx.test-d.tsx index ce1aec82043..b4a011042ef 100644 --- a/test-dts/tsx.test-d.tsx +++ b/test-dts/tsx.test-d.tsx @@ -1,4 +1,5 @@ // TSX w/ defineComponent is tested in defineComponent.test-d.tsx +import { betterDefineComponent } from 'packages/runtime-core/src/apiDefineComponent' import { KeepAlive, Suspense, From e201d2f046c46dc1fa26551ce28ac1a322ed1ad9 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Sun, 29 Aug 2021 13:40:41 +0100 Subject: [PATCH 42/42] chore: defineComponent changes --- .../runtime-core/src/apiDefineComponent.ts | 341 +----------------- .../src/componentPublicInstance.ts | 13 +- packages/runtime-core/src/h.ts | 19 +- test-dts/tsx.test-d.tsx | 4 + 4 files changed, 43 insertions(+), 334 deletions(-) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index cd4c363982d..854ea69832e 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -1,15 +1,10 @@ import { ComputedOptions, MethodOptions, - ComponentOptionsWithoutProps, - ComponentOptionsWithArrayProps, - ComponentOptionsWithObjectProps, ComponentOptionsMixin, RenderFunction, - ComponentOptionsBase, BettterComponentOptionsWithObjectProps, BetterComponentOptions, - BetterComponentOptionsAny, BettterComponentOptionsWithArrayProps, BettterComponentOptionsWithoutProps } from './componentOptions' @@ -18,271 +13,26 @@ import { AllowedComponentProps, ComponentCustomProps, Component, - GlobalDirectives, - GlobalComponents, BetterComponent } from './component' import { ExtractPropTypes, - ComponentPropsOptions, - ExtractDefaultPropTypes + ExtractDefaultPropTypes, + ComponentObjectPropsOptions } from './componentProps' -import { EmitsOptions, EmitsToProps } from './componentEmits' +import { EmitsOptions } from './componentEmits' import { isFunction } from '@vue/shared' import { VNodeProps } from './vnode' -import { - CreateComponentPublicInstance, - ComponentPublicInstanceConstructor, - RenderComponent -} from './componentPublicInstance' +import { RenderComponent } from './componentPublicInstance' import { Slots } from './componentSlots' import { Directive } from './directives' -import { ComponentObjectPropsOptions, PropType } from 'test-dts' export type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps -type FixS = T extends string[] - ? Record - : T - -export type DefineComponent< - PropsOrPropOptions = {}, - RawBindings = {}, - D = {}, - C extends ComputedOptions = ComputedOptions, - M extends MethodOptions = MethodOptions, - Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, - Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - E extends EmitsOptions = {}, - EE extends string = string, - S = any, - LC extends Record = {}, - Directives extends Record = {}, - Exposed extends string = string, - PP = PublicProps, - Props = Readonly>, - Defaults = ExtractDefaultPropTypes -> = ComponentPublicInstanceConstructor< - CreateComponentPublicInstance< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - FixS, - S, - PP & Props, - Defaults, - true, - LC & GlobalComponents, - Directives & GlobalDirectives, - Exposed - > & - Readonly> -> & /** - * just typescript - */ { __isDefineComponent?: true } & ComponentOptionsBase< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - S, - LC & GlobalComponents, - Directives & GlobalDirectives, - Exposed, - Defaults - > & - PP - -// defineComponent is a utility that is primarily used for type inference -// when declaring components. Type inference is provided in the component -// options (provided as the argument). The returned value has artificial types -// for TSX / manual render function / IDE support. - -// overload 1: direct setup function -// (uses user defined props interface) -export function defineComponent< - Props, - RawBindings = object, - E extends EmitsOptions = {}, - S = {} ->( - setup: ( - props: Readonly, - ctx: SetupContext> - ) => RawBindings | RenderFunction -): DefineComponent - -// 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 = EmitsOptions, - EE extends string = string, - S = any, - LC extends Record = {}, - Directives extends Record = {}, - Exposed extends string = string ->( - options: ComponentOptionsWithoutProps< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - S, - LC, - Directives, - Exposed - > -): DefineComponent< - Props, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - S, - LC, - Directives, - Exposed -> - -// 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 = any, - LC extends Record = {}, - Directives extends Record = {}, - Exposed extends string = string ->( - options: ComponentOptionsWithArrayProps< - PropNames, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - S, - LC, - Directives, - Exposed - > -): DefineComponent< - Readonly<{ [key in PropNames]?: any }>, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - S, - LC, - Directives, - Exposed -> - -// 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, - S = any, - LC extends Record = {}, - Directives extends Record = {}, - Exposed extends string = string, - Props = Readonly>, - Defaults = ExtractDefaultPropTypes ->( - options: ComponentOptionsWithObjectProps< - PropsOptions, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - S, - LC, - Directives, - Exposed, - Props, - Defaults - > -): DefineComponent< - PropsOptions, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - S, - LC, - Directives, - Exposed, - Props, - Defaults -> - -// implementation, close to no-op -export function defineComponent(options: unknown) { - return isFunction(options) ? { setup: options, name: options.name } : options -} - // Type Helper for defineComponent return -export type BetterDefineComponent< +export type DefineComponent< Props extends Record, Emits extends EmitsOptions = {}, S = {}, @@ -323,7 +73,7 @@ export type BetterDefineComponent< // overload 1: direct setup function // (uses user defined props interface) -export function betterDefineComponent< +export function defineComponent< Props extends Record = {}, RawBindings = {}, Emits extends EmitsOptions = {}, @@ -334,7 +84,7 @@ export function betterDefineComponent< props: Readonly, ctx: SetupContext> ) => RawBindings | RenderFunction -): { OOO: number } & BetterDefineComponent< +): DefineComponent< Props, Emits, S, @@ -366,7 +116,7 @@ export function betterDefineComponent< // overload 2: object format with no props // (uses user defined props interface) // return type is for Vetur and TSX support -export function betterDefineComponent< +export function defineComponent< Emits extends EmitsOptions = {}, S = {}, LC extends Record = {}, @@ -396,7 +146,7 @@ export function betterDefineComponent< Extends, Defaults > -): BetterDefineComponent< +): DefineComponent< {}, Emits, S, @@ -429,7 +179,7 @@ export function betterDefineComponent< // 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 betterDefineComponent< +export function defineComponent< PropNames extends string, Emits extends EmitsOptions = {}, S = {}, @@ -463,7 +213,7 @@ export function betterDefineComponent< Defaults, PropNames > -): BetterDefineComponent< +): DefineComponent< Props, Emits, S, @@ -498,7 +248,7 @@ export function betterDefineComponent< // overload 4: object format with object props declaration // see `ExtractPropTypes` in ./componentProps.ts -export function betterDefineComponent< +export function defineComponent< PropsOptions extends ComponentObjectPropsOptions = ComponentObjectPropsOptions, Emits extends EmitsOptions = {}, S = {}, @@ -534,7 +284,7 @@ export function betterDefineComponent< Defaults, PropsOptions > -): BetterDefineComponent< +): DefineComponent< Props, Emits, S, @@ -568,69 +318,6 @@ export function betterDefineComponent< > // implementation, close to no-op -export function betterDefineComponent(options: unknown) { +export function defineComponent(options: unknown) { return isFunction(options) ? { setup: options, name: options.name } : options } - -const xxx = betterDefineComponent({ - props: ['test'] -}) - -declare function test< - T extends BetterDefineComponent< - any, - any, - any, - any, - any, - any, - any, - any, - any, - any, - any, - any, - any, - any - > ->( - t: T -): T extends BetterComponent< - any, - any, - any, - any, - any, - any, - any, - any, - any, - any, - any, - any, - any, - infer O -> - ? O - : { nope: true } - -const r = test( - betterDefineComponent({ - // props: ['ttet'] - }) -) - -const rrr = betterDefineComponent({ - props: { - test: Number - } -}) - -const rt = betterDefineComponent<{ test: number }>({ - setup() { - return { - a: 2 - } - } -}) -rt.OOO diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index befecf9f295..486a3ed4595 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -50,6 +50,7 @@ import { UnionToIntersection } from './helpers/typeUtils' import { Directive } from './directives' import { installCompatInstanceProperties } from './compat/instance' import { Slot } from './componentSlots' +import { PublicProps } from './apiDefineComponent' /** * Custom properties added to component instances in any way and can be accessed through `this` @@ -306,7 +307,15 @@ export type BetterCreateComponentPublicInstance< PublicE, Readonly>, ExposedKeys< - ShallowUnwrapRef & + // Props + (MakeDefaultsOptional extends true + ? Partial & + Omit + : PublicP & PublicProps) & + EmitsToProps & + // /Props + + ShallowUnwrapRef & UnwrapNestedRefs & ExtractComputedReturns & PublicM, @@ -406,7 +415,7 @@ export type BetterComponentPublicInstance< > = { $: ComponentInternalInstance $data: D - $props: Props + $props: Props & PublicProps $attrs: Data $refs: Data diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index 39ba57d5cc3..753503ec367 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -328,7 +328,8 @@ declare const MyComp: BetterComponent< const r = betterH( MyComp, { - test: 2 + test: 2, + onHey(rrr) {} }, { default() { @@ -356,18 +357,26 @@ const x = betterH( ) const Comp = betterDefineComponent({ - props: { - test: Number - } + // props: ['test'] }) betterH( Comp, { - test: 1 + test: 2 }, {} ) declare function test(t: BetterComponent): boolean test(Comp) + +declare const MyComp2: Component<{ test: number }> + +h( + MyComp2, + { + test: 2 + }, + {} +) diff --git a/test-dts/tsx.test-d.tsx b/test-dts/tsx.test-d.tsx index b4a011042ef..74b1c1bdb89 100644 --- a/test-dts/tsx.test-d.tsx +++ b/test-dts/tsx.test-d.tsx @@ -66,3 +66,7 @@ expectType( ) // @ts-expect-error expectError() + +const EmptyComponent = betterDefineComponent({ props: {} }) + +;