From 6684c6334d38c5746a6048fa429b73d355997b33 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Fri, 4 Dec 2020 21:06:34 +0000 Subject: [PATCH] types: mixin and extends typing on data and setup (#2404) close #2350 --- packages/runtime-core/src/componentOptions.ts | 39 +++++++++++++++++-- test-dts/defineComponent.test-d.tsx | 36 +++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 76e61a44..2017b98f 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 c77feba0..e28a82e1 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