fix(types): make return type of defineComponent assignable to Component type (#1032)

fix #993
This commit is contained in:
Carlos Rodrigues 2020-04-24 18:22:58 +01:00 committed by GitHub
parent 28b4c317b4
commit f3a9b516bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 10 deletions

View File

@ -11,7 +11,8 @@ import {
watch, watch,
watchEffect, watchEffect,
onUnmounted, onUnmounted,
onErrorCaptured onErrorCaptured,
Component
} from '@vue/runtime-test' } from '@vue/runtime-test'
describe('Suspense', () => { describe('Suspense', () => {
@ -30,7 +31,7 @@ describe('Suspense', () => {
setup(props: any, { slots }: any) { setup(props: any, { slots }: any) {
const p = new Promise(resolve => { const p = new Promise(resolve => {
setTimeout(() => { setTimeout(() => {
resolve(() => h(comp, props, slots)) resolve(() => h<Component>(comp, props, slots))
}, delay) }, delay)
}) })
// in Node 12, due to timer/nextTick mechanism change, we have to wait // in Node 12, due to timer/nextTick mechanism change, we have to wait

View File

@ -5,7 +5,7 @@ import {
ComponentOptionsWithArrayProps, ComponentOptionsWithArrayProps,
ComponentOptionsWithObjectProps ComponentOptionsWithObjectProps
} from './componentOptions' } from './componentOptions'
import { SetupContext, RenderFunction } from './component' import { SetupContext, RenderFunction, FunctionalComponent } from './component'
import { ComponentPublicInstance } from './componentProxy' import { ComponentPublicInstance } from './componentProxy'
import { ExtractPropTypes, ComponentPropsOptions } from './componentProps' import { ExtractPropTypes, ComponentPropsOptions } from './componentProps'
import { EmitsOptions } from './componentEmits' import { EmitsOptions } from './componentEmits'
@ -34,7 +34,7 @@ export function defineComponent<Props, RawBindings = object>(
// public props // public props
VNodeProps & Props VNodeProps & Props
> >
} } & FunctionalComponent<Props>
// overload 2: object format with no props // overload 2: object format with no props
// (uses user defined props interface) // (uses user defined props interface)
@ -59,7 +59,7 @@ export function defineComponent<
E, E,
VNodeProps & Props VNodeProps & Props
> >
} } & ComponentOptionsWithoutProps<Props, RawBindings, D, C, M, E, EE>
// overload 3: object format with array props declaration // overload 3: object format with array props declaration
// props inferred as { [key in PropNames]?: any } // props inferred as { [key in PropNames]?: any }
@ -85,7 +85,7 @@ export function defineComponent<
): { ): {
// array props technically doesn't place any contraints on props in TSX // array props technically doesn't place any contraints on props in TSX
new (): ComponentPublicInstance<VNodeProps, RawBindings, D, C, M, E> new (): ComponentPublicInstance<VNodeProps, RawBindings, D, C, M, E>
} } & ComponentOptionsWithArrayProps<PropNames, RawBindings, D, C, M, E, EE>
// overload 4: object format with object props declaration // overload 4: object format with object props declaration
// see `ExtractPropTypes` in ./componentProps.ts // see `ExtractPropTypes` in ./componentProps.ts
@ -119,7 +119,7 @@ export function defineComponent<
E, E,
VNodeProps & ExtractPropTypes<PropsOptions, false> VNodeProps & ExtractPropTypes<PropsOptions, false>
> >
} } & ComponentOptionsWithObjectProps<PropsOptions, RawBindings, D, C, M, E, EE>
// implementation, close to no-op // implementation, close to no-op
export function defineComponent(options: unknown) { export function defineComponent(options: unknown) {

View File

@ -67,6 +67,11 @@ interface Constructor<P = any> {
new (): { $props: P } new (): { $props: P }
} }
// Excludes Component type from returned `defineComponent`
type NotDefinedComponent<T extends Component> = T extends Constructor
? never
: T
// The following is a series of overloads for providing props validation of // The following is a series of overloads for providing props validation of
// manually written render functions. // manually written render functions.
@ -110,8 +115,10 @@ export function h<P>(
// catch-all for generic component types // catch-all for generic component types
export function h(type: Component, children?: RawChildren): VNode export function h(type: Component, children?: RawChildren): VNode
export function h(
type: ComponentOptions | FunctionalComponent<{}>, // exclude `defineComponent`
export function h<Options extends ComponentOptions | FunctionalComponent<{}>>(
type: NotDefinedComponent<Options>,
props?: RawProps | null, props?: RawProps | null,
children?: RawChildren | RawSlots children?: RawChildren | RawSlots
): VNode ): VNode

View File

@ -1,4 +1,4 @@
import { expectError } from 'tsd' import { expectError, expectAssignable } from 'tsd'
import { import {
describe, describe,
h, h,
@ -131,3 +131,34 @@ describe('h support for generic component type', () => {
} }
foo({}) foo({})
}) })
// #993
describe('describeComponent extends Component', () => {
// functional
expectAssignable<Component>(
defineComponent((_props: { foo?: string; bar: number }) => {})
)
// typed props
expectAssignable<Component>(defineComponent({}))
// prop arrays
expectAssignable<Component>(
defineComponent({
props: ['a', 'b']
})
)
// prop object
expectAssignable<Component>(
defineComponent({
props: {
foo: String,
bar: {
type: Number,
required: true
}
}
})
)
})