Skip to content

Commit ef173f7

Browse files
committed
feat: properly type mount
This offers proper typings for the props given in the mounting options.
1 parent d0fd353 commit ef173f7

File tree

2 files changed

+108
-16
lines changed

2 files changed

+108
-16
lines changed

src/mount.ts

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import {
1010
Directive,
1111
Component,
1212
reactive,
13-
ComponentPublicInstance
13+
ComponentPublicInstance,
14+
ComponentOptionsWithObjectProps,
15+
ComponentOptionsWithArrayProps,
16+
ComponentOptionsWithoutProps,
17+
ExtractPropTypes
1418
} from 'vue'
1519

1620
import { createWrapper, VueWrapper } from './vue-wrapper'
@@ -25,9 +29,9 @@ import { stubComponents } from './stubs'
2529

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

28-
interface MountingOptions {
32+
interface MountingOptions<Props> {
2933
data?: () => Record<string, unknown>
30-
props?: Record<string, any>
34+
props?: Props
3135
slots?: {
3236
default?: Slot
3337
[key: string]: Slot
@@ -45,17 +49,41 @@ interface MountingOptions {
4549
stubs?: Record<string, any>
4650
}
4751

48-
export function mount<TestedComponent extends ComponentPublicInstance>(
52+
// Component declared with defineComponent
53+
export function mount<
54+
TestedComponent extends ComponentPublicInstance,
55+
PublicProps extends TestedComponent['$props']
56+
>(
4957
originalComponent: new () => TestedComponent,
50-
options?: MountingOptions
58+
options?: MountingOptions<PublicProps>
5159
): VueWrapper<TestedComponent>
52-
export function mount(
53-
originalComponent: Component,
54-
options?: MountingOptions
60+
// Component declared with { props: { ... } }
61+
export function mount<
62+
TestedComponent extends ComponentOptionsWithObjectProps,
63+
PublicProps extends ExtractPropTypes<TestedComponent['props']>
64+
>(
65+
originalComponent: TestedComponent,
66+
options?: MountingOptions<PublicProps>
67+
): VueWrapper<any>
68+
// Component declared with { props: [] }
69+
export function mount<
70+
TestedComponent extends ComponentOptionsWithArrayProps,
71+
PublicProps extends Record<string, any>
72+
>(
73+
originalComponent: TestedComponent,
74+
options?: MountingOptions<PublicProps>
75+
): VueWrapper<any>
76+
// Component declared with no props
77+
export function mount<
78+
TestedComponent extends ComponentOptionsWithoutProps,
79+
PublicProps extends Record<string, any>
80+
>(
81+
originalComponent: TestedComponent,
82+
options?: MountingOptions<PublicProps>
5583
): VueWrapper<any>
5684
export function mount(
5785
originalComponent: any,
58-
options?: MountingOptions
86+
options?: MountingOptions<any>
5987
): VueWrapper<any> {
6088
const component = { ...originalComponent }
6189

test-dts/index.d-test.ts

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,87 @@
1-
import { expectType } from 'tsd'
1+
import { expectError, expectType } from 'tsd'
22
import { defineComponent } from 'vue'
33
import { mount } from '../src'
44

5-
const App = defineComponent({
5+
const AppWithDefine = defineComponent({
66
props: {
7-
a: String
7+
a: {
8+
type: String,
9+
required: true
10+
}
811
},
912
template: ''
1013
})
1114

12-
let wrapper = mount(App)
15+
// accept props
16+
let wrapper = mount(AppWithDefine, {
17+
props: { a: 'Hello' }
18+
})
19+
// vm is properly typed
1320
expectType<string>(wrapper.vm.a)
1421

15-
const AppWithoutDefine = {
22+
// can receive extra props
23+
mount(AppWithDefine, {
24+
props: { a: 'Hello', b: 2 }
25+
})
26+
27+
// wrong prop type should not compile
28+
expectError(
29+
mount(AppWithDefine, {
30+
props: { a: 2 }
31+
})
32+
)
33+
34+
const AppWithProps = {
1635
props: {
17-
a: String
36+
a: {
37+
type: String,
38+
required: true
39+
}
1840
},
1941
template: ''
2042
}
2143

22-
wrapper = mount(AppWithoutDefine)
44+
// accept props
45+
wrapper = mount(AppWithProps, {
46+
props: { a: 'Hello' }
47+
})
48+
// vm is properly typed
2349
expectType<string>(wrapper.vm.a)
50+
51+
// can receive extra props
52+
mount(AppWithProps, {
53+
props: { a: 'Hello', b: 2 }
54+
})
55+
56+
// wrong prop type should not compile
57+
expectError(
58+
mount(AppWithProps, {
59+
props: { a: 2 }
60+
})
61+
)
62+
63+
const AppWithArrayProps = {
64+
props: ['a'],
65+
template: ''
66+
}
67+
68+
// accept props
69+
wrapper = mount(AppWithArrayProps, {
70+
props: { a: 'Hello' }
71+
})
72+
// vm is properly typed
73+
expectType<string>(wrapper.vm.a)
74+
75+
// can receive extra props
76+
mount(AppWithArrayProps, {
77+
props: { a: 'Hello', b: 2 }
78+
})
79+
80+
const AppWithoutProps = {
81+
template: ''
82+
}
83+
84+
// can receive extra props
85+
wrapper = mount(AppWithoutProps, {
86+
props: { b: 'Hello' }
87+
})

0 commit comments

Comments
 (0)