前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >typescript属性装饰器不生效的问题

typescript属性装饰器不生效的问题

原创
作者头像
easonxie
发布2023-07-25 10:32:11
6410
发布2023-07-25 10:32:11
举报

今天看项目的代码,发现有同事给一个typescript的属性装饰器添加了修饰,强制调用Object.getOwnPropertyDescriptor返回了Descriptor的内容,不清楚为啥这么写,了解后发现是为了解决属性装饰器不生效的问题。这里简单记录一下

一、问题背景

先来看个简单的装饰器例子

代码语言:javascript
复制
import 'reflect-metadata';

function simpleDecorator(target: any, propertyName: string) {
  console.log('Applying decorator to:', target, propertyName);

  let value = target[propertyName];

  const getter = () => {
    console.log(`Getting value of ${propertyName}:`, value);
    return value;
  };

  const setter = (newValue: any) => {
    console.log(`Setting value of ${propertyName}:`, newValue);
    value = newValue;
  };

  Object.defineProperty(target, propertyName, {
    get: getter,
    set: setter,
  });
}

class Example {
  @simpleDecorator
  public myProperty: string = 'Hello, world!';
}

const example = new Example();
console.log('Example:', example);
console.log('Getting myProperty:', example.myProperty);
example.myProperty = 'New value';
console.log('Getting myProperty:', example.myProperty);

这里会打印出来如下的内容

代码语言:javascript
复制
Applying decorator to: {} myProperty
Example: Example { myProperty: 'Hello, world!' }
Getting myProperty: Hello, world!
Getting myProperty: New value

这里会发现,setter相关的代码没有被执行,这是因为使用属性装饰器来修改属性的行为(例如拦截属性的访问或修改),则需要返回一个属性描述符。属性描述符包含有关属性的配置信息,例如属性是否可写(writable)、是否可枚举(enumerable)以及属性的getset函数等

二、问题解决

添加Object.getOwnPropertyDescriptor(target, propertyName) 返回属性描述符,即可解决问题

代码语言:javascript
复制
import 'reflect-metadata';

function simpleDecorator(target: any, propertyName: string) {
  console.log('Applying decorator to:', target, propertyName);

  let value = target[propertyName];

  const getter = () => {
    console.log(`Getting value of ${propertyName}:`, value);
    return value;
  };

  const setter = (newValue: any) => {
    console.log(`Setting value of ${propertyName}:`, newValue);
    value = newValue;
  };

  Object.defineProperty(target, propertyName, {
    get: getter,
    set: setter,
  });

  return Object.getOwnPropertyDescriptor(target, propertyName)
}

class Example {
  @simpleDecorator
  public myProperty: string = 'Hello, world!';
}

const example = new Example();
console.log('Example:', example);
console.log('Getting myProperty:', example.myProperty);
example.myProperty = 'New value';
console.log('Getting myProperty:', example.myProperty);

添加后可以看到返回了如下的内容

代码语言:javascript
复制
Example: Example {}
Getting value of myProperty: undefined
Getting myProperty: undefined
Setting value of myProperty: New value
Getting value of myProperty: New value
Getting myProperty: New value

可以看到setter函数已经成功执行了,不过控制台打印的example对象是空的,这是因为属性被装饰器处理不再存在对象上,但是仍然可以通过example.myProperty访问。不过这里这样处理后,初始化赋值的Hello, world!丢失了,这里可以使用下面的方式修复一下。

代码语言:javascript
复制
import 'reflect-metadata';

function simpleDecorator(initString: string) {
  return function (target: any, propertyName: string, ) {
    console.log('Applying decorator to:', target, propertyName);

    let value = initString; // 设置初始值

    const getter = () => {
      console.log(`Getting value of ${propertyName}:`, value);
      return value;
    };

    const setter = (newValue: any) => {
      console.log(`Setting value of ${propertyName}:`, newValue);
      value = newValue;
    };

    Object.defineProperty(target, propertyName, {
      get: getter,
      set: setter,
    });

    return Object.getOwnPropertyDescriptor(target, propertyName)
  }
}

class Example {
  @simpleDecorator('success ~!')
  public myProperty: string;
}

const example = new Example();
console.log('Example:', example);
console.log('Getting myProperty:', example.myProperty);
example.myProperty = 'New value';
console.log('Getting myProperty:', example.myProperty);

最后的结果如下

代码语言:javascript
复制
Applying decorator to: {} myProperty
Example: Example {}
Getting value of myProperty: success ~!
Getting myProperty: success ~!
Setting value of myProperty: New value
Getting value of myProperty: New value
Getting myProperty: New value

三、小结

这里分享了一点装饰器使用遇到的问题,实际开发,可能会遇到babel编译导致的属性装饰器失败的问题,原理就是因为没有返回属性描述符,这里可以修复下装饰器,强制返回Object.getOwnPropertyDescriptor(target, propertyName)解决

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、问题背景
  • 二、问题解决
  • 三、小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档