diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 333d18a30f3..8bfe814be25 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -16,7 +16,8 @@ import { import { ExtractPropTypes, ComponentPropsOptions, - ExtractDefaultPropTypes + ExtractDefaultPropTypes, + Prop } from './componentProps' import { EmitsOptions } from './componentEmits' import { isFunction } from '@vue/shared' @@ -26,6 +27,12 @@ import { ComponentPublicInstanceConstructor } from './componentPublicInstance' +export type PropObjectTyped> = { + [K in keyof T]: undefined extends T[K] + ? Prop + : Prop & { required: true } +} + export type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps @@ -179,6 +186,33 @@ export function defineComponent< > ): DefineComponent +// overload 5: Props interface passed as argument +// see `ExtractPropTypes` in ./componentProps.ts +export function defineComponent< + Props extends Record, + RawBindings = {}, + D = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, + Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, + Extends extends ComponentOptionsMixin = ComponentOptionsMixin, + E extends EmitsOptions = Record, + EE extends string = string, + PropOptions extends PropObjectTyped = PropObjectTyped +>( + options: ComponentOptionsWithObjectProps< + PropOptions, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE + > +): DefineComponent + // implementation, close to no-op export function defineComponent(options: unknown) { return isFunction(options) ? { setup: options, name: options.name } : options diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index e28a82e1d37..88915ee4b1a 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -960,6 +960,34 @@ describe('async setup', () => { vm.a = 2 }) +// type is correct +defineComponent<{ a?: string }>({ + props: { + a: String + }, + + setup(props) { + props.a + } +}) + +// error type is incorrect + +//@ts-expect-error invalid type on the prop definition +defineComponent<{ a: number }>({ + props: { + a: { + type: String, + required: true + } + }, + + // @ts-expect-error cannot resolve props type because of the mismatch + setup(props) { + props.a + } +}) + // check if defineComponent can be exported export default { // function components