From a655521937eaa6cab388e1b07a0f236d88366e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Thu, 30 Mar 2023 17:25:20 +0800 Subject: [PATCH] fix: functional component & public instance --- packages/compiler-sfc/src/compileScript.ts | 8 ++++++++ packages/dts-test/functionalComponent.test-d.tsx | 11 ++++++++++- packages/runtime-core/src/apiSetupHelpers.ts | 10 +++------- packages/runtime-core/src/component.ts | 10 +++++----- .../runtime-core/src/componentPublicInstance.ts | 6 ++++-- packages/runtime-core/src/componentSlots.ts | 15 +++++++++------ packages/runtime-core/src/h.ts | 8 ++++++-- 7 files changed, 45 insertions(+), 23 deletions(-) diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index f8f918ef795..812aa76e30f 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/packages/compiler-sfc/src/compileScript.ts @@ -726,6 +726,7 @@ export function compileScript( let propsOption = undefined let emitsOption = undefined let exposeOption = undefined + let slotsOption = undefined if (optionsRuntimeDecl.type === 'ObjectExpression') { for (const prop of optionsRuntimeDecl.properties) { if ( @@ -735,6 +736,7 @@ export function compileScript( if (prop.key.name === 'props') propsOption = prop if (prop.key.name === 'emits') emitsOption = prop if (prop.key.name === 'expose') exposeOption = prop + if (prop.key.name === 'slots') slotsOption = prop } } } @@ -757,6 +759,12 @@ export function compileScript( exposeOption ) } + if (slotsOption) { + error( + `${DEFINE_OPTIONS}() cannot be used to declare slots. Use ${DEFINE_SLOTS}() instead.`, + slotsOption + ) + } return true } diff --git a/packages/dts-test/functionalComponent.test-d.tsx b/packages/dts-test/functionalComponent.test-d.tsx index 383debcb7fe..9d4ad378794 100644 --- a/packages/dts-test/functionalComponent.test-d.tsx +++ b/packages/dts-test/functionalComponent.test-d.tsx @@ -1,4 +1,4 @@ -import { h, Text, FunctionalComponent, Component } from 'vue' +import { h, Text, FunctionalComponent, Component, SlotsType, VNode } from 'vue' import { expectType } from './utils' // simple function signature @@ -68,3 +68,12 @@ const Qux: FunctionalComponent<{}, ['foo', 'bar']> = (props, { emit }) => { } expectType(Qux) + +const Quux: FunctionalComponent<{}, {}, { default: [foo: number] }> = ( + props, + { emit, slots } +) => { + expectType<{ default: (foo: number) => VNode[] }>(slots) +} +expectType(Quux) +; diff --git a/packages/runtime-core/src/apiSetupHelpers.ts b/packages/runtime-core/src/apiSetupHelpers.ts index 9fd562081a4..c904a7cf4b6 100644 --- a/packages/runtime-core/src/apiSetupHelpers.ts +++ b/packages/runtime-core/src/apiSetupHelpers.ts @@ -156,9 +156,7 @@ export function defineOptions< C extends ComputedOptions = {}, M extends MethodOptions = {}, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, - Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - E extends EmitsOptions = EmitsOptions, - EE extends string = string + Extends extends ComponentOptionsMixin = ComponentOptionsMixin >( options?: ComponentOptionsWithoutProps< {}, @@ -167,10 +165,8 @@ export function defineOptions< C, M, Mixin, - Extends, - E, - EE - > & { emits?: undefined; expose?: undefined } + Extends + > & { emits?: undefined; expose?: undefined; slots?: undefined } ): void { if (__DEV__) { warnRuntimeUsage(`defineOptions`) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 4febe8929b0..f8562ff2d9c 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -28,7 +28,6 @@ import { normalizePropsOptions } from './componentProps' import { - Slots, initSlots, InternalSlots, SlotsType, @@ -126,12 +125,13 @@ export interface ComponentInternalOptions { export interface FunctionalComponent< P = {}, E extends EmitsOptions = {}, - S extends SlotsType = {} + S extends Record = {} > 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)[] + slots?: SlotsType inheritAttrs?: boolean displayName?: string compatConfig?: CompatConfig @@ -156,7 +156,7 @@ export type ConcreteComponent< M extends MethodOptions = MethodOptions > = | ComponentOptions - | FunctionalComponent + | FunctionalComponent /** * A type used in public APIs where a component type is expected. @@ -183,7 +183,7 @@ export type SetupContext< > = E extends any ? { attrs: Data - slots: [keyof S] extends [never] ? Slots : TypedSlots + slots: TypedSlots emit: EmitFn expose: (exposed?: Record) => void } diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index b376ef3e8ca..9997296b641 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -40,7 +40,7 @@ import { ComponentInjectOptions } from './componentOptions' import { EmitsOptions, EmitFn } from './componentEmits' -import { Slots, SlotsType } from './componentSlots' +import { SlotsType, TypedSlots } from './componentSlots' import { markAttrsAccessed } from './componentRenderUtils' import { currentRenderingInstance } from './componentRenderContext' import { warn } from './warning' @@ -164,6 +164,7 @@ export type CreateComponentPublicInstance< PublicC, PublicM, E, + S, PublicProps, PublicDefaults, MakeDefaultsOptional, @@ -180,6 +181,7 @@ export type ComponentPublicInstance< C extends ComputedOptions = {}, M extends MethodOptions = {}, E extends EmitsOptions = {}, + S extends SlotsType = {}, PublicProps = P, Defaults = {}, MakeDefaultsOptional extends boolean = false, @@ -195,7 +197,7 @@ export type ComponentPublicInstance< > $attrs: Data $refs: Data - $slots: Slots + $slots: TypedSlots $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 7ba69d04c53..e9619926434 100644 --- a/packages/runtime-core/src/componentSlots.ts +++ b/packages/runtime-core/src/componentSlots.ts @@ -36,13 +36,16 @@ export type SlotsType = Record> = { [SlotSymbol]?: T } -export type TypedSlots = Readonly< - Prettify<{ - [K in keyof NonNullable]: Slot< - NonNullable[K] + +export type TypedSlots = [keyof S] extends [never] + ? Slots + : Readonly< + Prettify<{ + [K in keyof NonNullable]: Slot< + NonNullable[K] + > + }> > - }> -> export type RawSlots = { [name: string]: unknown diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index 520f568e7a8..c3c65cdfdd5 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -120,8 +120,12 @@ export function h( ): VNode // functional component -export function h( - type: FunctionalComponent, +export function h< + P, + E extends EmitsOptions = {}, + S extends Record = {} +>( + type: FunctionalComponent, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots ): VNode