본문 바로가기

개발하자

TypeScript 게터를 메모하는 방법

반응형

TypeScript 게터를 메모하는 방법

나는 데코레이터를 사용하여 타입스크립트 게터를 메모하기 위해 다음과 같은 접근법을 사용하고 있지만 더 나은 방법이 있는지 알고 싶다. 나는 npm의 인기 패키지를 다음과 같이 사용하고 있다:

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
  }
}

My Component에서 두 개의 별도 기능을 사용하지 않고 대신 TypeScript getter에 데코레이터를 직접 추가할 수 있는 방법이 있습니까?

여기서 고려해야 할 사항 중 하나는 장식된 기능이 순수해야 한다는 것입니다(이 시나리오에서는). 하지만 만약 당신이 이것을 만족시키지 못하는 답을 가지고 있다면 그것을 무시해도 좋습니다. 왜냐하면 나는 이 문제에 접근하는 방법에 일반적인 관심이 있기 때문입니다.




데코레이터는 프로토타입 방법과 게터를 모두 지원하도록 확장할 수 있습니다:

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() {
    ...
  }



@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
  }
}

이를 통해 memoize 캐시에 사용할 속성을 결정하는 문자열 배열을 전달할 수 있습니다(이 경우 1개의 prop - clickCount - 는 변수이고 나머지 2개는 상수입니다).

메모지 옵션은 첫 번째 배열 인수만 메모화 목적으로 사용하도록 지정합니다.

아직도 이 코드가 얼마나 아름다운지 이해하려고 노력 중이야!


반응형