]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
types(defineComponent): Keep slot information on functional components pikax/keep_slots_information_on_functional_component 9721/head
authorCarlos Rodrigues <carlos@hypermob.co.uk>
Thu, 30 Nov 2023 15:29:57 +0000 (15:29 +0000)
committerCarlos Rodrigues <carlos@hypermob.co.uk>
Thu, 30 Nov 2023 15:29:57 +0000 (15:29 +0000)
packages/dts-test/defineComponent.test-d.tsx
packages/runtime-core/src/apiDefineComponent.ts
packages/runtime-core/src/h.ts

index b3f735ddad96504a220ebfe117cddcf317ef6f4a..a7c4421460e2e7463e36144a8cd337d3dd3a0820 100644 (file)
@@ -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,
index 092f679e9664fa4e9c4e2a804f16de5f89fe6443..5989b0c47d87808ef6921810f2f50fba96b5185c 100644 (file)
@@ -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)
index 4ca90262f2a95dcf445b472766f3af5df5cc0e54..a232b9e6a948f743cf9bb7cdc374a39a5c7c7a03 100644 (file)
@@ -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