Skip to content

Commit

Permalink
Merge pull request #274 from pikax/fix/set_default_props_as_optional
Browse files Browse the repository at this point in the history
types: fix mount infer prop type
  • Loading branch information
lmiller1990 committed Dec 19, 2020
2 parents fbe5f2b + 8a1c678 commit c5d3130
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 64 deletions.
15 changes: 9 additions & 6 deletions src/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ export function mount<V, P>(
props(Props: P): any
registerHooks(keys: string[]): void
},
options?: MountingOptions<P>
options?: MountingOptions<P & PublicProps>
): VueWrapper<ComponentPublicInstance<V>>

// Functional component with emits
export function mount<Props, E extends EmitsOptions = {}>(
originalComponent: FunctionalComponent<Props, E>,
options?: MountingOptions<Props>
options?: MountingOptions<Props & PublicProps>
): VueWrapper<ComponentPublicInstance<Props>>

// Component declared with defineComponent
Expand Down Expand Up @@ -105,7 +105,10 @@ export function mount<
Props,
Defaults
>,
options?: MountingOptions<Props, D>
options?: MountingOptions<
Partial<Defaults> & Omit<Props & PublicProps, keyof Defaults>,
D
>
): VueWrapper<
InstanceType<
DefineComponent<
Expand Down Expand Up @@ -148,7 +151,7 @@ export function mount<
Extends,
EE
>,
options?: MountingOptions<never, D>
options?: MountingOptions<Props & PublicProps, D>
): VueWrapper<
ComponentPublicInstance<Props, RawBindings, D, C, M, E, VNodeProps & Props>
>
Expand Down Expand Up @@ -180,7 +183,7 @@ export function mount<
EE,
Props
>,
options?: MountingOptions<Props, D>
options?: MountingOptions<Props & PublicProps, D>
): VueWrapper<ComponentPublicInstance<Props, RawBindings, D, C, M, E>>

// Component declared with { props: { ... } }
Expand Down Expand Up @@ -208,7 +211,7 @@ export function mount<
Extends,
EE
>,
options?: MountingOptions<ExtractPropTypes<PropsOptions>, D>
options?: MountingOptions<ExtractPropTypes<PropsOptions> & PublicProps, D>
): VueWrapper<
ComponentPublicInstance<
ExtractPropTypes<PropsOptions>,
Expand Down
14 changes: 12 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
Directive,
Plugin,
AppConfig,
VNode
VNode,
VNodeProps
} from 'vue'

interface RefSelector {
Expand Down Expand Up @@ -32,6 +33,15 @@ type SlotDictionary = {
[key: string]: Slot
}

// From vue next
// https://github.com/vuejs/vue-next/blob/1f2a652a9d2e3bec472fb1786a4c16d6ccfa1fb1/packages/runtime-core/src/h.ts#L53-L58
type RawProps = VNodeProps & {
// used to differ from a single VNode object as children
__v_isVNode?: never
// used to differ from Array children
[Symbol.iterator]?: never
} & Record<string, any>

export interface MountingOptions<Props, Data = {}> {
/**
* Overrides component's default data. Must be a function.
Expand All @@ -42,7 +52,7 @@ export interface MountingOptions<Props, Data = {}> {
* Sets component props when mounted.
* @see https://vue-test-utils.vuejs.org/v2/api/#props
*/
props?: Props
props?: (RawProps & Props) | ({} extends Props ? null : never)
/**
* @deprecated use `data` instead.
*/
Expand Down
93 changes: 59 additions & 34 deletions test-dts/mount.d-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,10 @@ expectType<string>(
// })
// )

// can not receive extra props
expectError(
mount(AppWithDefine, {
props: { a: 'Hello', c: 2 }
})
)
// allow extra props, like using `h()`
mount(AppWithDefine, {
props: { a: 'Hello', c: 2 }
})

// wrong prop type should not compile
expectError(
Expand All @@ -75,12 +73,9 @@ expectType<string>(
}).vm.a
)

// can't receive extra props
expectError(
mount(AppWithProps, {
props: { a: 'Hello', b: 2 }
})
)
mount(AppWithProps, {
props: { a: 'Hello', b: 2 }
})

// wrong prop type should not compile
expectError(
Expand Down Expand Up @@ -109,35 +104,25 @@ expectType<number>(
}).vm.b
)

// cannot receive extra props
// if they pass use object inside
expectError(
mount(
{
props: ['a']
},
{
props: {
b: 2
}
// allow extra props, like using `h()`
mount(
{
props: ['a']
},
{
props: {
b: 2
}
)
}
)

const AppWithoutProps = {
template: ''
}

// can't receive extra props
expectError(
mount(AppWithoutProps, {
props: { b: 'Hello' }
})
)

// except if explicitly cast
// allow extra props, like using `h()`
mount(AppWithoutProps, {
props: { b: 'Hello' } as never
props: { b: 'Hello' }
})

// Functional tests
Expand All @@ -150,7 +135,7 @@ expectError((props: { a: 1 }) => {}, {
})

expectType<number>(
mount((props: { a: 1 }, ctx) => {}, {
mount((props: { a: number }, ctx) => {}, {
props: {
a: 22
}
Expand Down Expand Up @@ -226,3 +211,43 @@ class ClassComponent extends Vue {
// @ts-expect-error it requires an argument
expectError(mount(ClassComponent, {}).vm.changeMessage())
mount(ClassComponent, {}).vm.changeMessage('')

// default props
const Foo = defineComponent({
props: {
bar: Boolean,
baz: String
},
template: ''
})

mount(Foo, {
props: {
baz: 'hello'
}
})

mount(Foo, {
props: {
bar: true
}
})

expectError(
mount(
defineComponent({
props: {
baz: String,
bar: {
type: Boolean,
required: true
}
}
}),
{
props: {
baz: 'hello'
}
}
)
)
33 changes: 11 additions & 22 deletions test-dts/shallowMount.d-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ let wrapper = shallowMount(AppWithDefine, {
// vm is properly typed
expectType<string>(wrapper.vm.a)

// can not receive extra props
expectError(
shallowMount(AppWithDefine, {
props: { a: 'Hello', c: 2 }
})
)
// allow extra props, like using `h()`
shallowMount(AppWithDefine, {
props: { a: 'Hello', c: 2 }
})

// wrong prop type should not compile
expectError(
Expand All @@ -53,12 +51,10 @@ expectType<string>(
}).vm.a
)

// can't receive extra props
expectError(
shallowMount(AppWithProps, {
props: { a: 'Hello', b: 2 }
})
)
// allow extra props, like using `h()`
shallowMount(AppWithProps, {
props: { a: 'Hello', b: 2 }
})

// wrong prop type should not compile
expectError(
Expand Down Expand Up @@ -89,16 +85,9 @@ const AppWithoutProps = {
template: ''
}

// can't receive extra props
expectError(
(wrapper = shallowMount(AppWithoutProps, {
props: { b: 'Hello' }
}))
)

// except if explicitly cast
shallowMount(AppWithoutProps, {
props: { b: 'Hello' } as never
// allow extra props, like using `h()`
wrapper = shallowMount(AppWithoutProps, {
props: { b: 'Hello' }
})

// class component
Expand Down

0 comments on commit c5d3130

Please sign in to comment.