TypeScript实现普通对象混入类 适配Vue类组件mapState状态混入
实现方案
首先基于Vue基类封装泛型Mixin函数,同时兼顾运行时属性挂载和TS类型推导:
import Vue from 'vue' /** * 接收普通对象,返回继承自Vue的类,实例同时包含Vue原生属性和传入对象的属性 * @param obj 要混入的属性对象,可直接传入mapState返回的映射结果 */ function ObjectMixin<T extends Record<string, any>>(obj: T): new () => Vue & T { return class extends Vue { constructor() { super() // 遍历属性做挂载适配 Object.entries(obj).forEach(([key, value]) => { // 兼容mapState返回的取值函数,转成实例getter if (typeof value === 'function') { Object.defineProperty(this, key, { get: value.bind(this), enumerable: true }) return } // 普通属性直接赋值 this[key] = value }) } } as any }
使用示例
和预期的调用方式完全一致,同时支持Vue原生属性和混入属性的类型提示:
class MyComponent extends ObjectMixin(smartModule.mapState(['someState'])) { created() { // 访问映射状态无类型报错,有正确的类型提示 console.log(this.someState) // Vue 原生属性/方法也可正常访问无报错 console.log(this.$route, this.$emit) } }
优化说明
- 解决了之前实现未继承Vue的问题,生成的类完全符合Vue类组件的继承要求
- 类型定义返回
Vue & T的实例类型,同时覆盖Vue原生属性和混入对象的属性,无额外类型报错 - 兼容mapState返回的取值函数场景,自动转成实例计算属性,运行时取值逻辑符合预期
- 仅用一处类型断言替代多处
@ts-ignore,写法更规范
注意事项
如果使用Vue3的类组件,只需将基类从Vue替换为vue-facing-decorator导出的基类即可,逻辑无需修改。如果你的smartModule.mapState返回的是普通值对象而非取值函数,可直接删除代码中的函数判断分支,用Object.assign(this, obj)简化赋值逻辑。
内容的提问来源于stack exchange,提问作者Alex l.
相关产品推荐
相关产品推荐

