Browse Source

fix(types): make generics with runtime props in defineComponent work (fix #11374) (#13119)

fixes #13763, fixes #11374
danyadev 1 month ago
parent
commit
cea3cf7586

+ 88 - 11
packages-private/dts-test/defineComponent.test-d.tsx

@@ -1402,7 +1402,7 @@ describe('function syntax w/ emits', () => {
 describe('function syntax w/ runtime props', () => {
   // with runtime props, the runtime props must match
   // manual type declaration
-  defineComponent(
+  const Comp1 = defineComponent(
     (_props: { msg: string }) => {
       return () => {}
     },
@@ -1411,7 +1411,34 @@ describe('function syntax w/ runtime props', () => {
     },
   )
 
+  // @ts-expect-error bar isn't specified in props definition
   defineComponent(
+    (_props: { msg: string }) => {
+      return () => {}
+    },
+    {
+      props: ['msg', 'bar'],
+    },
+  )
+
+  defineComponent(
+    (_props: { msg: string; bar: string }) => {
+      return () => {}
+    },
+    {
+      props: ['msg'],
+    },
+  )
+
+  expectType<JSX.Element>(<Comp1 msg="1" />)
+  // @ts-expect-error msg type is incorrect
+  expectType<JSX.Element>(<Comp1 msg={1} />)
+  // @ts-expect-error msg is missing
+  expectType<JSX.Element>(<Comp1 />)
+  // @ts-expect-error bar doesn't exist
+  expectType<JSX.Element>(<Comp1 msg="1" bar="2" />)
+
+  const Comp2 = defineComponent(
     <T extends string>(_props: { msg: T }) => {
       return () => {}
     },
@@ -1420,7 +1447,36 @@ describe('function syntax w/ runtime props', () => {
     },
   )
 
+  // @ts-expect-error bar isn't specified in props definition
   defineComponent(
+    <T extends string>(_props: { msg: T }) => {
+      return () => {}
+    },
+    {
+      props: ['msg', 'bar'],
+    },
+  )
+
+  defineComponent(
+    <T extends string>(_props: { msg: T; bar: T }) => {
+      return () => {}
+    },
+    {
+      props: ['msg'],
+    },
+  )
+
+  expectType<JSX.Element>(<Comp2 msg="1" />)
+  expectType<JSX.Element>(<Comp2<string> msg="1" />)
+  // @ts-expect-error msg type is incorrect
+  expectType<JSX.Element>(<Comp2 msg={1} />)
+  // @ts-expect-error msg is missing
+  expectType<JSX.Element>(<Comp2 />)
+  // @ts-expect-error bar doesn't exist
+  expectType<JSX.Element>(<Comp2 msg="1" bar="2" />)
+
+  // Note: generics aren't supported with object runtime props
+  const Comp3 = defineComponent(
     <T extends string>(_props: { msg: T }) => {
       return () => {}
     },
@@ -1431,37 +1487,58 @@ describe('function syntax w/ runtime props', () => {
     },
   )
 
-  // @ts-expect-error string prop names don't match
   defineComponent(
-    (_props: { msg: string }) => {
+    // @ts-expect-error bar isn't specified in props definition
+    <T extends string>(_props: { msg: T }) => {
       return () => {}
     },
     {
-      props: ['bar'],
+      props: {
+        bar: String,
+      },
     },
   )
 
   defineComponent(
-    (_props: { msg: string }) => {
+    // @ts-expect-error generics aren't supported with object runtime props
+    <T extends string>(_props: { msg: T; bar: T }) => {
       return () => {}
     },
     {
       props: {
-        // @ts-expect-error prop type mismatch
-        msg: Number,
+        msg: String,
       },
     },
   )
 
-  // @ts-expect-error prop keys don't match
+  expectType<JSX.Element>(<Comp3 msg="1" />)
+  // @ts-expect-error generics aren't supported with object runtime props
+  expectType<JSX.Element>(<Comp3<string> msg="1" />)
+  // @ts-expect-error msg type is incorrect
+  expectType<JSX.Element>(<Comp3 msg={1} />)
+  // @ts-expect-error msg is missing
+  expectType<JSX.Element>(<Comp3 />)
+  // @ts-expect-error bar doesn't exist
+  expectType<JSX.Element>(<Comp3 msg="1" bar="2" />)
+
+  // @ts-expect-error string prop names don't match
   defineComponent(
-    (_props: { msg: string }, ctx) => {
+    (_props: { msg: string }) => {
+      return () => {}
+    },
+    {
+      props: ['bar'],
+    },
+  )
+
+  defineComponent(
+    (_props: { msg: string }) => {
       return () => {}
     },
     {
       props: {
-        msg: String,
-        bar: String,
+        // @ts-expect-error prop type mismatch
+        msg: Number,
       },
     },
   )

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

@@ -157,7 +157,7 @@ export function defineComponent<
     ctx: SetupContext<E, S>,
   ) => RenderFunction | Promise<RenderFunction>,
   options?: Pick<ComponentOptions, 'name' | 'inheritAttrs'> & {
-    props?: (keyof Props)[]
+    props?: (keyof NoInfer<Props>)[]
     emits?: E | EE[]
     slots?: S
   },