]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
types: improve h() and TSX type inference
authorEvan You <yyx990803@gmail.com>
Thu, 31 Oct 2019 16:43:05 +0000 (12:43 -0400)
committerEvan You <yyx990803@gmail.com>
Thu, 31 Oct 2019 16:43:05 +0000 (12:43 -0400)
- Should allow extraneous props as attrs in TSX
- Should check props when using constructor type returned by
  createComponent() in h()

packages/runtime-core/__tests__/apiCreateComponent.spec.tsx
packages/runtime-core/src/apiCreateComponent.ts
packages/runtime-core/src/apiOptions.ts
packages/runtime-core/src/h.ts

index f02b089f079c4b7eda8703ac730f584d8db09e68..3fd21122ca666bffdbc530d1b31b2484d0b4d3a4 100644 (file)
@@ -67,7 +67,14 @@ test('createComponent type inference', () => {
     }
   })
   // test TSX props inference
-  ;<MyComponent a={1} b="foo" dd={['foo']} ddd={['foo']} />
+  ;<MyComponent
+    a={1}
+    b="foo"
+    dd={['foo']}
+    ddd={['foo']}
+    // should allow extraneous as attrs
+    class="bar"
+  />
 })
 
 test('type inference w/ optional props declaration', () => {
index 6353f4f0dbe23a18511a5e78c47cd97bd4fd5257..1c01cc6f86c9ae42358cbf7f55045199e9e7f402 100644 (file)
@@ -9,13 +9,31 @@ import { SetupContext, RenderFunction } from './component'
 import { ComponentPublicInstance } from './componentProxy'
 import { ExtractPropTypes } from './componentProps'
 import { isFunction } from '@vue/shared'
+import { Ref } from '@vue/reactivity'
+
+interface BaseProps {
+  [key: string]: any
+  key?: string | number
+  ref?: string | Ref | Function
+}
 
 // overload 1: direct setup function
 // (uses user defined props interface)
+// __isConstructor: true is a type-only differentiator to avoid returned
+// constructor type from being matched as an options object in h()
 export function createComponent<Props, RawBindings = object>(
   setup: (props: Props, ctx: SetupContext) => RawBindings | RenderFunction
 ): {
-  new (): ComponentPublicInstance<Props, RawBindings>
+  __isConstructor: true
+  new (): ComponentPublicInstance<
+    Props,
+    RawBindings,
+    {},
+    {},
+    {},
+    // public props
+    BaseProps & Props
+  >
 }
 
 // overload 2: object format with no props
@@ -30,11 +48,19 @@ export function createComponent<
 >(
   options: ComponentOptionsWithoutProps<Props, RawBindings, D, C, M>
 ): {
-  new (): ComponentPublicInstance<Props, RawBindings, D, C, M>
+  __isConstructor: true
+  new (): ComponentPublicInstance<
+    Props,
+    RawBindings,
+    D,
+    C,
+    M,
+    BaseProps & Props
+  >
 }
 
 // overload 3: object format with array props declaration
-// props inferred as { [key in PropNames]?: unknown }
+// props inferred as { [key in PropNames]?: any }
 // return type is for Vetur and TSX support
 export function createComponent<
   PropNames extends string,
@@ -45,13 +71,9 @@ export function createComponent<
 >(
   options: ComponentOptionsWithArrayProps<PropNames, RawBindings, D, C, M>
 ): {
-  new (): ComponentPublicInstance<
-    { [key in PropNames]?: unknown },
-    RawBindings,
-    D,
-    C,
-    M
-  >
+  __isConstructor: true
+  // array props technically doesn't place any contraints on props in TSX
+  new (): ComponentPublicInstance<BaseProps, RawBindings, D, C, M>
 }
 
 // overload 4: object format with object props declaration
@@ -65,14 +87,15 @@ export function createComponent<
 >(
   options: ComponentOptionsWithObjectProps<PropsOptions, RawBindings, D, C, M>
 ): {
+  __isConstructor: true
   // for Vetur and TSX support
   new (): ComponentPublicInstance<
-    ExtractPropTypes<PropsOptions>,
+    ExtractPropTypes<PropsOptions, false>,
     RawBindings,
     D,
     C,
     M,
-    ExtractPropTypes<PropsOptions, false>
+    BaseProps & ExtractPropTypes<PropsOptions, false>
   >
 }
 
index 4054e3d39927ffbc1adf43c666d3d8175be9c07e..7f764ddc0c04f60698d996f5072e9c435dda1849 100644 (file)
@@ -65,6 +65,10 @@ export interface ComponentOptionsBase<
   components?: Record<string, Component>
   directives?: Record<string, Directive>
   inheritAttrs?: boolean
+
+  // type-only differentiator to separate OptionWihtoutProps from a constructor
+  // type returned by createComponent()
+  __isConstructor?: never
 }
 
 export type ComponentOptionsWithoutProps<
index b7a9ff49998a4d536f0d347ce235a5e15ad79de6..f0ff4ed57b9cc0a04bfc9e5c4c10c1c28a92d629 100644 (file)
@@ -133,9 +133,7 @@ export function h<P>(
 ): VNode
 export function h<P extends string>(
   type: ComponentOptionsWithArrayProps<P>,
-  // TODO for now this doesn't really do anything, but it would become useful
-  // if we make props required by default
-  props?: (RawProps & { [key in P]?: any }) | null,
+  props?: RawProps | null,
   children?: RawChildren | RawSlots
 ): VNode
 export function h<P>(