Skip to content

Commit

Permalink
feat: support custom class component (#1212)
Browse files Browse the repository at this point in the history
  • Loading branch information
agileago authored Jan 5, 2022
1 parent a56375f commit 54c27fc
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 3 deletions.
22 changes: 21 additions & 1 deletion src/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import {
ComputedOptions,
ComponentPropsOptions,
ComponentOptions,
ConcreteComponent
ConcreteComponent,
Prop
} from 'vue'

import { MountingOptions, Slot } from './types'
Expand Down Expand Up @@ -73,6 +74,25 @@ function getInstanceOptions(
return resultOptions
}

// Class component (without vue-class-component) - no props
export function mount<V>(
originalComponent: {
new (...args: any[]): V
__vccOpts: any
},
options?: MountingOptions<any> & Record<string, any>
): VueWrapper<ComponentPublicInstance<V>>

// Class component (without vue-class-component) - props
export function mount<V, P>(
originalComponent: {
new (...args: any[]): V
__vccOpts: any
defaultProps?: Record<string, Prop<any>> | string[]
},
options?: MountingOptions<P & PublicProps> & Record<string, any>
): VueWrapper<ComponentPublicInstance<V>>

// Class component - no props
export function mount<V>(
originalComponent: {
Expand Down
83 changes: 81 additions & 2 deletions test-dts/mount.d-test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { expectError, expectType } from './index'
import {
ComponentOptions,
DefineComponent,
defineComponent,
FunctionalComponent
FunctionalComponent,
getCurrentInstance,
h,
ref,
SetupContext,
Prop,
VNodeChild
} from 'vue'
import { Options, Vue } from 'vue-class-component'
import { mount } from '../src'
Expand Down Expand Up @@ -179,7 +186,7 @@ declare const FunctionalComponentEmit: FunctionalComponent<
level: number
},
{ hello: (foo: string, bar: string) => void }
>
>

mount(FunctionalComponent)
mount(defineComponent(FunctionalComponent))
Expand Down Expand Up @@ -211,6 +218,78 @@ class ClassComponent extends Vue {
expectError(mount(ClassComponent, {}).vm.changeMessage())
mount(ClassComponent, {}).vm.changeMessage('')

// region custom class component implement
class CustomClassComponent<Props extends {} = {}> {
static defaultProps?: Record<string, Prop<any>> | string[]
private static __vccValue?: ComponentOptions
static get __vccOpts(): ComponentOptions {
if (this.__vccValue) return this.__vccValue
const CompConstructor = this
return (this.__vccValue = {
name: CompConstructor.name,
props: CompConstructor.defaultProps,
setup(props, ctx) {
const instance = new CompConstructor()
return instance.render.bind(instance)
}
})
}
constructor() {
const instance = getCurrentInstance()!
this.props = instance.props as Props
// @ts-expect-error no explicit setupContext on instance
this.context = instance.setupContext as SetupContext
}

props: Props
get $props() {
return this.props
}
context: SetupContext
render(): VNodeChild {}
}
class NoPropCustomClassComponent extends CustomClassComponent {
count = ref(0)
changeCount(count: number) {
this.count.value = count
}
render() {
return h('div', `hello world ${this.count.value}`)
}
}

// @ts-expect-error changeCount expects an argument
expectError(mount(NoPropCustomClassComponent, {}).vm.changeCount())
mount(NoPropCustomClassComponent, {}).vm.changeCount(2)

interface CustomClassComponentProps {
size: 'small' | 'large'
age?: number
}

class WithPropCustomClassComponent extends CustomClassComponent<CustomClassComponentProps> {
static defaultProps: (keyof CustomClassComponentProps)[] = ['size', 'age']
count = ref(0)
changeCount(count: number) {
this.count.value = count
}
render() {
return h('div', `hello world ${this.count.value}${this.props.size}`)
}
}

expectError(
// @ts-expect-error should has props error
mount<WithPropCustomClassComponent, CustomClassComponentProps>(WithPropCustomClassComponent, {
props: {}
})
)
mount<WithPropCustomClassComponent, CustomClassComponentProps>(WithPropCustomClassComponent, {
props: { size: 'small' }
})

// endregion

// default props
const Foo = defineComponent({
props: {
Expand Down

0 comments on commit 54c27fc

Please sign in to comment.