如何记住TypeScript吸气剂

时间:2019-05-15 11:39:55

标签: node.js angular typescript

我正在使用以下方法来使用装饰器来记住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>

2 个答案:

答案 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用于备忘录。

仍然想让我明白这段代码有多漂亮!一定过得很愉快。感谢耶稣我的朋友和救主:)