From dd5a26b1f83f9e2ceff4b798732a4f057e517f15 Mon Sep 17 00:00:00 2001 From: ktsn Date: Sun, 17 Dec 2017 22:00:19 +0900 Subject: [PATCH 1/3] feat: add mixins helper --- src/declarations.ts | 2 +- src/index.ts | 2 +- src/util.ts | 12 +++++++++++- test/test-babel.js | 29 ++++++++++++++++++++++++++++- test/test.ts | 29 ++++++++++++++++++++++++++++- 5 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/declarations.ts b/src/declarations.ts index e1c349f..af7981f 100644 --- a/src/declarations.ts +++ b/src/declarations.ts @@ -1,6 +1,6 @@ import Vue, { ComponentOptions } from 'vue' -export type VueClass = { new (...args: any[]): V } & typeof Vue +export type VueClass = { new (...args: any[]): V & Vue } & typeof Vue export type DecoratedClass = VueClass & { // Property, method and parameter decorators created by `createDecorator` helper diff --git a/src/index.ts b/src/index.ts index 16b230a..f9e6f09 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ import Vue, { ComponentOptions } from 'vue' import { VueClass } from './declarations' import { componentFactory, $internalHooks } from './component' -export { createDecorator, VueDecorator } from './util' +export { createDecorator, VueDecorator, mixins } from './util' function Component (options: ComponentOptions & ThisType): >(target: VC) => VC function Component >(target: VC): VC diff --git a/src/util.ts b/src/util.ts index 4793454..58f6f8e 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,5 +1,5 @@ import Vue, { ComponentOptions } from 'vue' -import { DecoratedClass } from './declarations' +import { VueClass, DecoratedClass } from './declarations' export const noop = () => {} @@ -31,6 +31,16 @@ export function createDecorator (factory: (options: ComponentOptions, key: } } +export function mixins (CtorA: VueClass): VueClass +export function mixins (CtorA: VueClass, CtorB: VueClass): VueClass +export function mixins (CtorA: VueClass, CtorB: VueClass, CtorC: VueClass): VueClass +export function mixins (CtorA: VueClass, CtorB: VueClass, CtorC: VueClass, CtorD: VueClass): VueClass +export function mixins (CtorA: VueClass, CtorB: VueClass, CtorC: VueClass, CtorD: VueClass, CtorE: VueClass): VueClass +export function mixins (...Ctors: VueClass[]): VueClass +export function mixins (...Ctors: VueClass[]): VueClass { + return Vue.extend({ mixins: Ctors }) +} + export function isPrimitive (value: any): boolean { const type = typeof value return value == null || (type !== "object" && type !== "function") diff --git a/test/test-babel.js b/test/test-babel.js index ecbade1..f42cccb 100644 --- a/test/test-babel.js +++ b/test/test-babel.js @@ -1,4 +1,4 @@ -import Component, { createDecorator } from '../lib' +import Component, { createDecorator, mixins } from '../lib' import { expect } from 'chai' import * as td from 'testdouble' import Vue from 'vue' @@ -121,4 +121,31 @@ describe('vue-class-component with Babel', () => { expect(MyComp.foo).to.equal('foo') expect(MyComp.bar()).to.equal('bar') }) + + it('mixin helper', function () { + @Component + class MixinA extends Vue { + valueA = 'hello' + } + + @Component + class MixinB extends Vue { + valueB = 123 + } + + @Component + class MyComp extends mixins(MixinA, MixinB) { + test () { + this.valueA = 'hi' + this.valueB = 456 + } + } + + const vm = new MyComp() + expect(vm.valueA).to.equal('hello') + expect(vm.valueB).to.equal(123) + vm.test() + expect(vm.valueA).to.equal('hi') + expect(vm.valueB).to.equal(456) + }) }) diff --git a/test/test.ts b/test/test.ts index cae0c5d..66c834d 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,4 +1,4 @@ -import Component, { createDecorator } from '../lib' +import Component, { createDecorator, mixins } from '../lib' import { expect } from 'chai' import * as td from 'testdouble' import Vue, { ComputedOptions } from 'vue' @@ -342,4 +342,31 @@ describe('vue-class-component', () => { console.warn = originalWarn } }) + + it('mixin helper', function () { + @Component + class MixinA extends Vue { + valueA = 'hello' + } + + @Component + class MixinB extends Vue { + valueB = 123 + } + + @Component + class MyComp extends mixins(MixinA, MixinB) { + test () { + this.valueA = 'hi' + this.valueB = 456 + } + } + + const vm = new MyComp() + expect(vm.valueA).to.equal('hello') + expect(vm.valueB).to.equal(123) + vm.test() + expect(vm.valueA).to.equal('hi') + expect(vm.valueB).to.equal(456) + }) }) From f12df40cebe8c92dd03d4771f8726941e22dd151 Mon Sep 17 00:00:00 2001 From: ktsn Date: Thu, 15 Feb 2018 15:44:40 +0900 Subject: [PATCH 2/3] docs: add a guide for mixins --- README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/README.md b/README.md index 11976a3..7dec223 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,40 @@ export default class App extends Vue { You may also want to check out the `@prop` and `@watch` decorators provided by [vue-property-decorators](https://github.com/kaorun343/vue-property-decorator). +### Using Mixins + +vue-class-component provides `mixin` helper function to use [mixin](https://vuejs.org/v2/guide/mixins.html) in class style manner. By using `mixin` helper, TypeScript can infer mixin type and inherit the type on the component type. + +Example of declaring a mixin: + +``` js +// mixin.js +import Vue from 'vue' +import Component from 'vue-class-component' + +// You can declare a mixin as the same style as components. +@Component +export class MyMixin extends Vue { + mixinValue = 'Hello' +} +``` + +Example of using a mixin: + +``` js +import Component, { mixin } from 'vue-class-component' +import MyMixin from './mixin.js' + +// Use `mixin` helper function instead of `Vue`. +// `mixin` can receive any number of arguments. +@Component +export class MyComp extends mixin(MyMixin) { + created () { + console.log(this.mixinValue) // -> Hello + } +} +``` + ### Create Custom Decorators 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: From e4c18ddbb1f2fbb97486591cda7c1769b969ef55 Mon Sep 17 00:00:00 2001 From: ktsn Date: Fri, 16 Feb 2018 13:51:38 +0900 Subject: [PATCH 3/3] docs: fix typos --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7dec223..68d48c7 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ You may also want to check out the `@prop` and `@watch` decorators provided by [ ### Using Mixins -vue-class-component provides `mixin` helper function to use [mixin](https://vuejs.org/v2/guide/mixins.html) in class style manner. By using `mixin` helper, TypeScript can infer mixin type and inherit the type on the component type. +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. Example of declaring a mixin: @@ -97,13 +97,13 @@ export class MyMixin extends Vue { Example of using a mixin: ``` js -import Component, { mixin } from 'vue-class-component' +import Component, { mixins } from 'vue-class-component' import MyMixin from './mixin.js' -// Use `mixin` helper function instead of `Vue`. -// `mixin` can receive any number of arguments. +// Use `mixins` helper function instead of `Vue`. +// `mixins` can receive any number of arguments. @Component -export class MyComp extends mixin(MyMixin) { +export class MyComp extends mixins(MyMixin) { created () { console.log(this.mixinValue) // -> Hello }