Skip to content

Commit

Permalink
feat: properly type mount
Browse files Browse the repository at this point in the history
This offers proper typings for the props given in the mounting options.
  • Loading branch information
cexbrayat committed Apr 17, 2020
1 parent be92e32 commit 31f6101
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 22 deletions.
46 changes: 37 additions & 9 deletions src/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import {
Directive,
Component,
reactive,
ComponentPublicInstance
ComponentPublicInstance,
ComponentOptionsWithProps,
ComponentOptionsWithArrayProps,
ComponentOptionsWithoutProps,
ExtractPropTypes
} from 'vue'

import { createWrapper, VueWrapper } from './vue-wrapper'
Expand All @@ -21,9 +25,9 @@ import { stubComponents } from './stubs'

type Slot = VNode | string | { render: Function }

interface MountingOptions {
interface MountingOptions<Props> {
data?: () => Record<string, unknown>
props?: Record<string, any>
props?: Props
slots?: {
default?: Slot
[key: string]: Slot
Expand All @@ -41,17 +45,41 @@ interface MountingOptions {
stubs?: Record<string, any>
}

export function mount<TestedComponent extends ComponentPublicInstance>(
// Component declared with defineComponent
export function mount<
TestedComponent extends ComponentPublicInstance,
PublicProps extends TestedComponent['$props']
>(
originalComponent: new () => TestedComponent,
options?: MountingOptions
options?: MountingOptions<PublicProps>
): VueWrapper<TestedComponent>
export function mount(
originalComponent: Component,
options?: MountingOptions
// Component declared with { props: { ... } }
export function mount<
TestedComponent extends ComponentOptionsWithProps,
PublicProps extends ExtractPropTypes<TestedComponent['props']>
>(
originalComponent: TestedComponent,
options?: MountingOptions<PublicProps>
): VueWrapper<any>
// Component declared with { props: [] }
export function mount<
TestedComponent extends ComponentOptionsWithArrayProps,
PublicProps extends Record<string, any>
>(
originalComponent: TestedComponent,
options?: MountingOptions<PublicProps>
): VueWrapper<any>
// Component declared with no props
export function mount<
TestedComponent extends ComponentOptionsWithoutProps,
PublicProps extends Record<string, any>
>(
originalComponent: TestedComponent,
options?: MountingOptions<PublicProps>
): VueWrapper<any>
export function mount(
originalComponent: any,
options?: MountingOptions
options?: MountingOptions<any>
): VueWrapper<any> {
const component = { ...originalComponent }

Expand Down
2 changes: 1 addition & 1 deletion src/vue-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,5 @@ export function createWrapper<T extends ComponentPublicInstance>(
events: Record<string, unknown[]>,
setProps: (props: Record<string, any>) => void
): VueWrapper<T> {
return new VueWrapper<T>(vm, events, setProps)
return new VueWrapper(vm, events, setProps)
}
78 changes: 71 additions & 7 deletions test-dts/index.d-test.ts
Original file line number Diff line number Diff line change
@@ -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<string>(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<string>(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<string>(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' }
})
5 changes: 0 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1218,11 +1218,6 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.4.tgz#76c3cb3a12909510f52e5dc04a6298cdf9504ffd"
integrity sha512-oVeL12C6gQS/GAExndigSaLxTrKpQPxewx9bOcwfvJiJge4rr7wNaph4J+ns5hrmIV2as5qxqN8YKthn9qh0jw==

"@types/node@12.12.35":
version "12.12.35"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.35.tgz#1e61b226c14380f4384f70cfe49a65c2c553ad2b"
integrity sha512-ASYsaKecA7TUsDrqIGPNk3JeEox0z/0XR/WsJJ8BIX/9+SkMSImQXKWfU/yBrSyc7ZSE/NPqLu36Nur0miCFfQ==

"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
Expand Down

0 comments on commit 31f6101

Please sign in to comment.