Skip to content

Commit cdcbfe5

Browse files
authored
feat: add mixins helper (vuejs#224)
* feat: add mixins helper * docs: add a guide for mixins * docs: fix typos
1 parent ed4d289 commit cdcbfe5

File tree

6 files changed

+103
-5
lines changed

6 files changed

+103
-5
lines changed

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,40 @@ export default class App extends Vue {
7676

7777
You may also want to check out the `@prop` and `@watch` decorators provided by [vue-property-decorators](https://github.com/kaorun343/vue-property-decorator).
7878

79+
### Using Mixins
80+
81+
vue-class-component provides `mixins` helper function to use [mixins](https://vuejs.org/v2/guide/mixins.html) in class style manner. By using `mixins` helper, TypeScript can infer mixin types and inherit them on the component type.
82+
83+
Example of declaring a mixin:
84+
85+
``` js
86+
// mixin.js
87+
import Vue from 'vue'
88+
import Component from 'vue-class-component'
89+
90+
// You can declare a mixin as the same style as components.
91+
@Component
92+
export class MyMixin extends Vue {
93+
mixinValue = 'Hello'
94+
}
95+
```
96+
97+
Example of using a mixin:
98+
99+
``` js
100+
import Component, { mixins } from 'vue-class-component'
101+
import MyMixin from './mixin.js'
102+
103+
// Use `mixins` helper function instead of `Vue`.
104+
// `mixins` can receive any number of arguments.
105+
@Component
106+
export class MyComp extends mixins(MyMixin) {
107+
created () {
108+
console.log(this.mixinValue) // -> Hello
109+
}
110+
}
111+
```
112+
79113
### Create Custom Decorators
80114

81115
You can extend the functionality of this library by creating your own decorators. vue-class-component provides `createDecorator` helper to create custom decorators. `createDecorator` expects a callback function as the 1st argument and the callback will receive following arguments:

src/declarations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Vue, { ComponentOptions } from 'vue'
22

3-
export type VueClass<V extends Vue> = { new (...args: any[]): V } & typeof Vue
3+
export type VueClass<V> = { new (...args: any[]): V & Vue } & typeof Vue
44

55
export type DecoratedClass = VueClass<Vue> & {
66
// Property, method and parameter decorators created by `createDecorator` helper

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Vue, { ComponentOptions } from 'vue'
22
import { VueClass } from './declarations'
33
import { componentFactory, $internalHooks } from './component'
44

5-
export { createDecorator, VueDecorator } from './util'
5+
export { createDecorator, VueDecorator, mixins } from './util'
66

77
function Component <V extends Vue>(options: ComponentOptions<V> & ThisType<V>): <VC extends VueClass<V>>(target: VC) => VC
88
function Component <VC extends VueClass<Vue>>(target: VC): VC

src/util.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Vue, { ComponentOptions } from 'vue'
2-
import { DecoratedClass } from './declarations'
2+
import { VueClass, DecoratedClass } from './declarations'
33

44
export const noop = () => {}
55

@@ -31,6 +31,16 @@ export function createDecorator (factory: (options: ComponentOptions<Vue>, key:
3131
}
3232
}
3333

34+
export function mixins <A> (CtorA: VueClass<A>): VueClass<A>
35+
export function mixins <A, B> (CtorA: VueClass<A>, CtorB: VueClass<B>): VueClass<A & B>
36+
export function mixins <A, B, C> (CtorA: VueClass<A>, CtorB: VueClass<B>, CtorC: VueClass<C>): VueClass<A & B & C>
37+
export function mixins <A, B, C, D> (CtorA: VueClass<A>, CtorB: VueClass<B>, CtorC: VueClass<C>, CtorD: VueClass<D>): VueClass<A & B & C & D>
38+
export function mixins <A, B, C, D, E> (CtorA: VueClass<A>, CtorB: VueClass<B>, CtorC: VueClass<C>, CtorD: VueClass<D>, CtorE: VueClass<E>): VueClass<A & B & C & D & E>
39+
export function mixins <T> (...Ctors: VueClass<Vue>[]): VueClass<T>
40+
export function mixins (...Ctors: VueClass<Vue>[]): VueClass<Vue> {
41+
return Vue.extend({ mixins: Ctors })
42+
}
43+
3444
export function isPrimitive (value: any): boolean {
3545
const type = typeof value
3646
return value == null || (type !== "object" && type !== "function")

test/test-babel.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Component, { createDecorator } from '../lib'
1+
import Component, { createDecorator, mixins } from '../lib'
22
import { expect } from 'chai'
33
import * as td from 'testdouble'
44
import Vue from 'vue'
@@ -121,4 +121,31 @@ describe('vue-class-component with Babel', () => {
121121
expect(MyComp.foo).to.equal('foo')
122122
expect(MyComp.bar()).to.equal('bar')
123123
})
124+
125+
it('mixin helper', function () {
126+
@Component
127+
class MixinA extends Vue {
128+
valueA = 'hello'
129+
}
130+
131+
@Component
132+
class MixinB extends Vue {
133+
valueB = 123
134+
}
135+
136+
@Component
137+
class MyComp extends mixins(MixinA, MixinB) {
138+
test () {
139+
this.valueA = 'hi'
140+
this.valueB = 456
141+
}
142+
}
143+
144+
const vm = new MyComp()
145+
expect(vm.valueA).to.equal('hello')
146+
expect(vm.valueB).to.equal(123)
147+
vm.test()
148+
expect(vm.valueA).to.equal('hi')
149+
expect(vm.valueB).to.equal(456)
150+
})
124151
})

test/test.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Component, { createDecorator } from '../lib'
1+
import Component, { createDecorator, mixins } from '../lib'
22
import { expect } from 'chai'
33
import * as td from 'testdouble'
44
import Vue, { ComputedOptions } from 'vue'
@@ -342,4 +342,31 @@ describe('vue-class-component', () => {
342342
console.warn = originalWarn
343343
}
344344
})
345+
346+
it('mixin helper', function () {
347+
@Component
348+
class MixinA extends Vue {
349+
valueA = 'hello'
350+
}
351+
352+
@Component
353+
class MixinB extends Vue {
354+
valueB = 123
355+
}
356+
357+
@Component
358+
class MyComp extends mixins(MixinA, MixinB) {
359+
test () {
360+
this.valueA = 'hi'
361+
this.valueB = 456
362+
}
363+
}
364+
365+
const vm = new MyComp()
366+
expect(vm.valueA).to.equal('hello')
367+
expect(vm.valueB).to.equal(123)
368+
vm.test()
369+
expect(vm.valueA).to.equal('hi')
370+
expect(vm.valueB).to.equal(456)
371+
})
345372
})

0 commit comments

Comments
 (0)