From ef173f778cc676e33da179ca7b8798bd16ce524f Mon Sep 17 00:00:00 2001 From: cexbrayat Date: Thu, 16 Apr 2020 18:54:58 +0200 Subject: [PATCH] feat: properly type mount This offers proper typings for the props given in the mounting options. --- src/mount.ts | 46 +++++++++++++++++++----- test-dts/index.d-test.ts | 78 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 108 insertions(+), 16 deletions(-) diff --git a/src/mount.ts b/src/mount.ts index a125b86d4..a2ba87fa3 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -10,7 +10,11 @@ import { Directive, Component, reactive, - ComponentPublicInstance + ComponentPublicInstance, + ComponentOptionsWithObjectProps, + ComponentOptionsWithArrayProps, + ComponentOptionsWithoutProps, + ExtractPropTypes } from 'vue' import { createWrapper, VueWrapper } from './vue-wrapper' @@ -25,9 +29,9 @@ import { stubComponents } from './stubs' type Slot = VNode | string | { render: Function } -interface MountingOptions { +interface MountingOptions { data?: () => Record - props?: Record + props?: Props slots?: { default?: Slot [key: string]: Slot @@ -45,17 +49,41 @@ interface MountingOptions { stubs?: Record } -export function mount( +// Component declared with defineComponent +export function mount< + TestedComponent extends ComponentPublicInstance, + PublicProps extends TestedComponent['$props'] +>( originalComponent: new () => TestedComponent, - options?: MountingOptions + options?: MountingOptions ): VueWrapper -export function mount( - originalComponent: Component, - options?: MountingOptions +// Component declared with { props: { ... } } +export function mount< + TestedComponent extends ComponentOptionsWithObjectProps, + PublicProps extends ExtractPropTypes +>( + originalComponent: TestedComponent, + options?: MountingOptions +): VueWrapper +// Component declared with { props: [] } +export function mount< + TestedComponent extends ComponentOptionsWithArrayProps, + PublicProps extends Record +>( + originalComponent: TestedComponent, + options?: MountingOptions +): VueWrapper +// Component declared with no props +export function mount< + TestedComponent extends ComponentOptionsWithoutProps, + PublicProps extends Record +>( + originalComponent: TestedComponent, + options?: MountingOptions ): VueWrapper export function mount( originalComponent: any, - options?: MountingOptions + options?: MountingOptions ): VueWrapper { const component = { ...originalComponent } diff --git a/test-dts/index.d-test.ts b/test-dts/index.d-test.ts index c454c832e..e5a2daea6 100644 --- a/test-dts/index.d-test.ts +++ b/test-dts/index.d-test.ts @@ -1,23 +1,87 @@ -import { expectType } from 'tsd' +import { expectError, expectType } from 'tsd' import { defineComponent } from 'vue' import { mount } from '../src' -const App = defineComponent({ +const AppWithDefine = defineComponent({ props: { - a: String + a: { + type: String, + required: true + } }, template: '' }) -let wrapper = mount(App) +// accept props +let wrapper = mount(AppWithDefine, { + props: { a: 'Hello' } +}) +// vm is properly typed expectType(wrapper.vm.a) -const AppWithoutDefine = { +// can receive extra props +mount(AppWithDefine, { + props: { a: 'Hello', b: 2 } +}) + +// wrong prop type should not compile +expectError( + mount(AppWithDefine, { + props: { a: 2 } + }) +) + +const AppWithProps = { props: { - a: String + a: { + type: String, + required: true + } }, template: '' } -wrapper = mount(AppWithoutDefine) +// accept props +wrapper = mount(AppWithProps, { + props: { a: 'Hello' } +}) +// vm is properly typed expectType(wrapper.vm.a) + +// can receive extra props +mount(AppWithProps, { + props: { a: 'Hello', b: 2 } +}) + +// wrong prop type should not compile +expectError( + mount(AppWithProps, { + props: { a: 2 } + }) +) + +const AppWithArrayProps = { + props: ['a'], + template: '' +} + +// accept props +wrapper = mount(AppWithArrayProps, { + props: { a: 'Hello' } +}) +// vm is properly typed +expectType(wrapper.vm.a) + +// can receive extra props +mount(AppWithArrayProps, { + props: { a: 'Hello', b: 2 } +}) + +const AppWithoutProps = { + template: '' +} + +// can receive extra props +wrapper = mount(AppWithoutProps, { + props: { b: 'Hello' } +})