diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 76e61a44e..2017b98f6 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -59,6 +59,7 @@ import { import { warn } from './warning' import { VNodeChild } from './vnode' import { callWithAsyncErrorHandling } from './errorHandling' +import { UnionToIntersection } from './helpers/typeUtils' /** * Interface for declaring custom options. @@ -80,6 +81,19 @@ export interface ComponentCustomOptions {} export type RenderFunction = () => VNodeChild +type ExtractOptionProp = T extends ComponentOptionsBase< + infer P, + any, + any, + any, + any, + any, + any, + any +> + ? unknown extends P ? {} : P + : {} + export interface ComponentOptionsBase< Props, RawBindings, @@ -97,7 +111,9 @@ export interface ComponentOptionsBase< ComponentCustomOptions { setup?: ( this: void, - props: Props, + props: Props & + UnionToIntersection> & + UnionToIntersection>, ctx: SetupContext ) => Promise | RawBindings | RenderFunction | void name?: string @@ -358,8 +374,24 @@ interface LegacyOptions< // since that leads to some sort of circular inference and breaks ThisType // for the entire component. data?: ( - this: CreateComponentPublicInstance, - vm: CreateComponentPublicInstance + this: CreateComponentPublicInstance< + Props, + {}, + {}, + {}, + MethodOptions, + Mixin, + Extends + >, + vm: CreateComponentPublicInstance< + Props, + {}, + {}, + {}, + MethodOptions, + Mixin, + Extends + > ) => D computed?: C methods?: M @@ -590,6 +622,7 @@ export function applyOptions( deferredData.forEach(dataFn => resolveData(instance, dataFn, publicThis)) } if (dataOptions) { + // @ts-ignore dataOptions is not fully type safe resolveData(instance, dataOptions, publicThis) } if (__DEV__) { diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index c77feba02..e28a82e1d 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -445,10 +445,18 @@ describe('with mixins', () => { const MixinD = defineComponent({ mixins: [MixinA], data() { + //@ts-expect-error computed are not available on data() + expectError(this.dC1) + //@ts-expect-error computed are not available on data() + expectError(this.dC2) + return { d: 4 } }, + setup(props) { + expectType(props.aP1) + }, computed: { dC1(): number { return this.d + this.a @@ -467,6 +475,34 @@ describe('with mixins', () => { required: true } }, + + data(vm) { + expectType(vm.a) + expectType(vm.b) + expectType(vm.c) + expectType(vm.d) + + // should also expose declared props on `this` + expectType(this.a) + expectType(this.aP1) + expectType(this.aP2) + expectType(this.b) + expectType(this.bP1) + expectType(this.c) + expectType(this.d) + + return {} + }, + + setup(props) { + expectType(props.z) + // props + expectType(props.aP1) + expectType(props.aP2) + expectType(props.bP1) + expectType(props.bP2) + expectType(props.z) + }, render() { const props = this.$props // props