我正在使用以下方法来使用装饰器来记住TypeScript getter,但想知道是否有更好的方法。我正在使用npm中流行的memoizee软件包,如下所示:
import { memoize } from '@app/decorators/memoize'
export class MyComponent {
@memoize()
private static memoizeEyeSrc(clickCount, maxEyeClickCount, botEyesDir) {
return clickCount < maxEyeClickCount ? botEyesDir + '/bot-eye-tiny.png' : botEyesDir + '/bot-eye-black-tiny.png'
}
get leftEyeSrc() {
return MyComponent.memoizeEyeSrc(this.eyes.left.clickCount, this.maxEyeClickCount, this.botEyesDir)
}
}
和备忘录装饰器是:
// decorated method must be pure
import * as memoizee from 'memoizee'
export const memoize = (): MethodDecorator => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const func = descriptor.value
descriptor.value = memoizee(func)
return descriptor
}
}
有没有办法在MyComponent中不使用两个单独的函数,而是直接将装饰器添加到TypeScript getter?
这里要考虑的是,装饰函数必须是纯函数(在这种情况下),但是如果您有一个不满意的答案,可以随意忽略它,因为我对解决这个问题有普遍的兴趣。 / p>
答案 0 :(得分:2)
装饰器可以扩展为支持原型方法和吸气剂:
export const memoize = (): MethodDecorator => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
if ('value' in descriptor) {
const func = descriptor.value;
descriptor.value = memoizee(func);
} else if ('get' in descriptor) {
const func = descriptor.get;
descriptor.get = memoizee(func);
}
return descriptor;
}
}
直接在吸气剂上使用:
@memoize()
get leftEyeSrc() {
...
}
答案 1 :(得分:0)
基于@estus答案,这是我最终想到的:
@memoize(['this.eyes.left.clickCount'])
get leftEyeSrc() {
return this.eyes.left.clickCount < this.maxEyeClickCount ? this.botEyesDir + '/bot-eye-tiny.png' : this.botEyesDir + '/bot-eye-black-tiny.png'
}
备忘录装饰器是:
// decorated method must be pure when not applied to a getter
import { get } from 'lodash'
import * as memoizee from 'memoizee'
// noinspection JSUnusedGlobalSymbols
const options = {
normalizer(args) {
return args[0]
}
}
const memoizedFuncs = {}
export const memoize = (props: string[] = []): MethodDecorator => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
props = props.map(prop => prop.replace(/^this\./, ''))
if ('value' in descriptor) {
const valueFunc = descriptor.value
descriptor.value = memoizee(valueFunc)
} else if ('get' in descriptor) {
const getFunc = descriptor.get
// args is used here solely for determining the memoize cache - see the options object
memoizedFuncs[propertyKey] = memoizee((args: string[], that) => {
const func = getFunc.bind(that)
return func()
}, options)
descriptor.get = function() {
const args: string[] = props.map(prop => get(this, prop))
return memoizedFuncs[propertyKey](args, this)
}
}
return descriptor
}
}
这允许传递一个字符串数组,用于确定将哪些属性用于备忘缓存(在这种情况下,只有1个prop-clickCount-是变量,其他2个是常数)。
备忘录选项表明仅将memoizee((args: string[], that) => {...})
的第一个数组arg用于备忘录。
仍然想让我明白这段代码有多漂亮!一定过得很愉快。感谢耶稣我的朋友和救主:)