如何为类创建实用程序



我做了
什么 我最初的方法是使用以下返回类装饰器的 mixin:

function createMixin (behaviour: any, sharedBehaviour: any = {}): any {
const instanceKeys: any = Reflect.ownKeys(behaviour)
const sharedKeys: any = Reflect.ownKeys(sharedBehaviour)
const typeTag = Symbol(`isa`)
function _mixin (clazz: Function): Function {
for (let property of instanceKeys) {
Object.defineProperty(clazz.prototype, property, {
value: behaviour[property],
writable: true
})
}
Object.defineProperty(clazz.prototype, typeTag, { value: true })
return clazz
}
for (let property of sharedKeys) {
Object.defineProperty(_mixin, property, {
value: sharedBehaviour[property],
enumerable: sharedBehaviour.propertyIsEnumerable(property)
})
}
Object.defineProperty(_mixin, Symbol.hasInstance, {
value: (i: any) => !!i[typeTag]
})
return _mixin
}
export const customUtil = createMixin({
customUtil (event: any) {
console.log(this)
}
})

所以以后可以使用 util 来装饰类,并且可以毫无问题地访问目标类的这个:

import { customUtil } from 'utils'
@customUtil
export default class ComponentClass extends Vue {
someClassMethod() {
this.customUtil() // successfully outputs the whole class in the console
}
}

但这会导致 tslinter 警告TS2339: Property 'customUtil' does not exist on type 'ComponentClass'.

问题
1.是否有可能通过以某种方式"键入"mixin 实用程序 2 分配给类的方法来解决 linter 问题
。如果有另一种方法可以拥有实用程序函数/类,这些函数/类可以毫无问题地访问使用它们的类,并使用简单的方法来附加它们?

这个问题已经在其他线程中讨论过,也是 TypeScript github 中的一个悬而未决的问题。但是有两种方法可以解决这个问题。

1:类型转换

您可以只键入this以忘记类上下文或使用必要的信息对其进行增强。

import { customUtil } from 'utils'
@customUtil
export default class ComponentClass extends Vue {
someClassMethod() {
(this as any).customUtil(); // Now the linter will be fine but you will lose type safety
(this as any as {customUtil: (event:any) => void}).customUtil(); // This works and you could/should extract the type. 
}
}

但如您所见,这并不理想。

2:真正的打字稿混合

你可以使用真正的TypeScript Mixins而不是Decorators:

实用工具

type Constructor<T = {}> = new (...args: any[]) => T;
// The Mixin
export function WithUtils<TBase extends Constructor>(Base: TBase) {
return class extends Base {
customUtil (event?: any) { // Actually, 'event' needs to be optional
console.log(this)
}
};
}
// A Base class so you can just extend if needed
export const UtilsBase = WithUtils(class {});

元件

export default class ComponentClass extends WithUtils(Vue) {
someClassMethod() {
this.customUtil() // successfully outputs the whole class in the console
}
}

类不是从 Vue 扩展的

export default class SomeClass extends UtilsBase {
someClassMethod() {
this.customUtil() // successfully outputs the whole class in the console
}
}
// alternatively, you can use the Mixin with an unnamed class
export default class SomeClass extends WithUtils(class {}) {
someClassMethod() {
this.customUtil() // successfully outputs the whole class in the console
}
}

最新更新