前言
有个项目,需要使用 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 到底是什么样的。
解决方案
这里有许许多多种,我收集整理一下。
-
简单粗暴法 (as 强制转换) 极度不推荐
跟着上面的内容:
(this as any).sayHello();
报错消失,但是这样会让代码很脏,组件阅读性差的同时,还要写很多 as 转换,同时,转换 any 让 typeScript 的意义荡然无存,还不如不用。
-
继承 mixins (只适合当个 mixin)
mixinA:
export const MixinA = Vue.extend({
method: {
sayHello() {
// ...
}
}
})
components:
export default MixinA.extend({
mixins: [MixinA],
create() {
this.sayHello();
}
})
也不报错了,通过继承 mixinA 的方式,让编译器知道里面有什么东西。
缺点:违背 mixins 的设计初衷,mixins 本身就支持多 mixin 混入。
优点:简单粗暴。
-
使用 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
缺点:使用习惯的修改。 还是比较支持的。
-
升级为 Vue3。
Vue 官方在 3 后,有为 mixin 做的处理。(具体没有了解过,虽然很吐槽这种升级的方式)
-
遵循 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],
-
自己写接口
interface mixinState {
sayHello: () => {}
}
export default (Vue as VueConstructor<Vue & mixinState>).extend({
name: 'Home',
create() {
this.sayHello();
}
})
本质上与 第 5 种 是一样的。
缺点:要写许多接口。
-
使用 vue-property-decorator 等。
使用类型注解的方式。没研究,不喜欢这种写法。
|
请发表评论