ソースを参照

types(defineComponent): Keep slot information on functional components

Carlos Rodrigues 2 年 前
コミット
e8f693eda6

+ 35 - 0
packages/dts-test/defineComponent.test-d.tsx

@@ -1497,6 +1497,41 @@ describe('should work when props type is incompatible with setup returned type '
   expectType<SizeType>(CompA.$props.size)
 })
 
+// #9649
+describe('should keep slots on functional component', () => {
+  const Comp = defineComponent(
+    (
+      _1: {},
+      _2: SetupContext<
+        {},
+        SlotsType<{ default?(data: { foo: string; bar: number }): any }>
+      >
+    ) =>
+      () =>
+        null,
+    {
+      slots: Object as SlotsType<{ default: { foo: string; bar: number } }>
+    }
+  )
+
+  h(Comp, {
+    default: data => {
+      expectType<{ foo: string; bar: number }>(data)
+      // @ts-expect-error not any
+      expectType<string>(data)
+      return null
+    }
+  })
+  h(Comp, null, {
+    default: data => {
+      expectType<{ foo: string; bar: number }>(data)
+      // @ts-expect-error not any
+      expectType<string>(data)
+      return null
+    }
+  })
+})
+
 import {
   DefineComponent,
   ComponentOptionsMixin,

+ 2 - 2
packages/runtime-core/src/apiDefineComponent.ts

@@ -111,7 +111,7 @@ export function defineComponent<
     emits?: E | EE[]
     slots?: S
   }
-): (props: Props & EmitsToProps<E>) => any
+): (props: Props & EmitsToProps<E> & S) => any
 export function defineComponent<
   Props extends Record<string, any>,
   E extends EmitsOptions = {},
@@ -127,7 +127,7 @@ export function defineComponent<
     emits?: E | EE[]
     slots?: S
   }
-): (props: Props & EmitsToProps<E>) => any
+): (props: Props & EmitsToProps<E> & S) => any
 
 // overload 2: object format with no props
 // (uses user defined props interface)

+ 16 - 2
packages/runtime-core/src/h.ts

@@ -11,7 +11,7 @@ import {
 import { Teleport, TeleportProps } from './components/Teleport'
 import { Suspense, SuspenseProps } from './components/Suspense'
 import { isObject, isArray } from '@vue/shared'
-import { RawSlots } from './componentSlots'
+import { RawSlots, SlotsType, UnwrapSlotsType } from './componentSlots'
 import {
   FunctionalComponent,
   Component,
@@ -119,6 +119,17 @@ export function h(
   children?: RawChildren | RawSlots
 ): VNode
 
+// functional component
+export function h<
+  P,
+  E extends EmitsOptions = {},
+  S extends Record<string, any> = {}
+>(
+  type: FunctionalComponent<P, E, S>,
+  children?:
+    | RawChildren
+    | (P extends SlotsType<any> ? UnwrapSlotsType<P> : never)
+): VNode
 // functional component
 export function h<
   P,
@@ -127,7 +138,10 @@ export function h<
 >(
   type: FunctionalComponent<P, E, S>,
   props?: (RawProps & P) | ({} extends P ? null : never),
-  children?: RawChildren | RawSlots
+  children?:
+    | RawChildren
+    | RawSlots
+    | (P extends SlotsType<any> ? UnwrapSlotsType<P> : {})
 ): VNode
 
 // catch-all for generic component types