Vue 在 typeScript 中写mixins。

前言

有个项目,需要使用 mixins 来管理一些通用方法。同时该项目使用 Typescript。

问题

编译器报错,提示组件中没有该 mixin 中的内容。具体看一下代码。

MixinA:

export const MixinA = {
    method: {
        sayHello() {
            // ...
        }
    }
}

component:

export default Vue.extend({
    mixins: [MixinA],
    create() {
        this.sayHello();   // <- 报错位置.
    }
})

报错:

Property 'sayHello' does not exist on type 'CombinedVueInstance<Vue, unknown, unknown, unknown, Readonly<Record<never, any>>>'.Vetur(2339)

根据报错信息,可以看到是 Vetur 这个插件报的错。
究其原因,还是因为 TypeScript 不够聪明,没法知道 Mixin 到底是什么样的。

解决方案

这里有许许多多种,我收集整理一下。

  1. 简单粗暴法 (as 强制转换) 极度不推荐

    跟着上面的内容:

    (this as any).sayHello();
    

    报错消失,但是这样会让代码很脏,组件阅读性差的同时,还要写很多 as 转换,同时,转换 any 让 typeScript 的意义荡然无存,还不如不用。

  2. 继承 mixins (只适合当个 mixin)

    mixinA:

    export const MixinA = Vue.extend({
        method: {
            sayHello() {
                // ...
            }
        }
    })
    

    components:

    export default MixinA.extend({
        mixins: [MixinA],
        create() {
            this.sayHello();
        }
    })
    

    也不报错了,通过继承 mixinA 的方式,让编译器知道里面有什么东西。

    缺点:违背 mixins 的设计初衷,mixins 本身就支持多 mixin 混入。

    优点:简单粗暴。

  3. 使用 vue-typed-mixins

    import Vue from 'vue'
    import mixins from 'vue-typed-mixins'
    
    const mixinsA = Vue.extend({
    data() {
        return {
        foo: 'test'
        }
    }
    })
    
    const mixinsB = Vue.extend({
    data() {
        return {
        bar: 123
        }
    }
    })
    
    const App = mixins(mixinsA, mixinsB).extend({
    data() {
        return {
        value: true
        }
    },
    
    computed: {
        concat(): string {
        return `${this.foo} ${this.bar} ${this.value}`
        }
    }
    })
    

    优点:可以混合,多个 mixin
    缺点:使用习惯的修改。 还是比较支持的。

  4. 升级为 Vue3。
    Vue 官方在 3 后,有为 mixin 做的处理。(具体没有了解过,虽然很吐槽这种升级的方式)

  5. 遵循 Vue 和 TS 原则的一种解决方式.

    mixinA :

    
    // mixinA.vue
    导出默认 Vue.extend({…})
    

    mixinB:

    // mixinB.vue
    导出默认 Vue.extend({…})
    

    那么使用这两个的组件可以定义为:

    export default (Vue as VueConstructor<Vue & InstanceType<typeof MixinA>& InstanceType<typeof
    MixinB>>).extend({
    mixins: [MixinA, MixinB],
    
    
  6. 自己写接口

    interface mixinState {
    sayHello: () => {}
    }
    
    export default (Vue as VueConstructor<Vue & mixinState>).extend({
    name: 'Home',
    create() {
        this.sayHello();
    }
    })
    
    

    本质上与 第 5 种 是一样的。
    缺点:要写许多接口。

  7. 使用 vue-property-decorator 等。

    使用类型注解的方式。没研究,不喜欢这种写法。

posted @ 2021-06-21 16:11  志在指尖  阅读(1883)  评论(0编辑  收藏  举报