简体   繁体   English

如何创建一个装饰器来生成一个新的 class 属性,该属性是装饰属性的映射或转换

[英]How to create a decorator that produces a new class property that is a mapping or transformation of the decorated property

I'm trying to figure out how to write a decorator that consumes an already existing class property and generates a mapped or transformed version of that property that also updates every time the value of the original property updates.我试图弄清楚如何编写一个装饰器,它使用已经存在的 class 属性并生成该属性的映射或转换版本,每次原始属性的值更新时也会更新。

For example, @upperCase would generate a new property (with the key `${DECORATED_PROPERTY}_UPPERCASE` ) that converts the string to upper case, and @double would generate a new property (with the key `${DECORATED_PROPERTY}_DOUBLE` ) that doubles the value of every number in an array.例如, @upperCase将生成一个新属性(使用键`${DECORATED_PROPERTY}_UPPERCASE` )将字符串转换为大写, @double将生成一个新属性(使用键`${DECORATED_PROPERTY}_DOUBLE` )将数组中每个数字的值加倍。

class MyClass {
  @upperCase word = 'hamburger';
  @double numbers = [1, 2, 3, 4];
}

const foo = new MyClass();
console.log(foo.word_UPPERCASE); // 'HAMBURGER'
console.log(foo.numbers_DOUBLE); // [2, 4, 6, 8]

foo.word = 'new word';
// See the derived property update in accordance with the original when the original changes value
foo.word_UPPERCASE = 'NEW WORD';

I've played around with Object.defineProperty and the get and set properties on it, but nothing seems to work.我玩过Object.defineProperty以及它的getset属性,但似乎没有任何效果。 For example, when I try this implementation for @upperCase :例如,当我为@upperCase尝试此实现时:

export function upperCase(target:any, propertyKey:string) {
  let value:string = target[propertyKey];

  const getter = function () {
    return value.toUpperCase();      // Error below gets thrown at this line
  }

  const setter = function (newVal:string) {
    value = newVal;
  }

  Object.defineProperty(target, `${propertyKey}_UPPERCASE`, {
    get: getter,
    set: setter,
  })
}

and use it in the class like @upperCase word:string = 'foobar';并在 class 中使用它,例如@upperCase word:string = 'foobar'; , if I then console.log(this['word_UPPERCASE']) , I get the following error: ,如果我然后console.log(this['word_UPPERCASE']) ,我会收到以下错误:

TypeError: can't access property "toUpperCase", value is undefined thrown at the line commented above where the getter is trying to return value.toUpperCase() . TypeError: can't access property "toUpperCase", value is undefined在上面注释的行中抛出getter试图返回value.toUpperCase()

Thanks to Aluan Haddad , the answer is simply:感谢Aluan Haddad ,答案很简单:

function upperCase(target:any, propertyKey:string) {

  Object.defineProperty(target, `${propertyKey}_UPPERCASE`, {
    get: function () {
      return this[propertyKey].toUpperCase();
    },
    enumerable: true,
  })

}

To use:要使用:

class MyClass {
  @upperCase word:string = 'hello';
  word_UPPERCASE!:string;

  constructor() {
    console.log(this.word);
    console.log(this.word_UPPERCASE);
  }
}

// Output:
// hello 
// HELLO

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM