使用 TypeScript 自定义装饰器给类的属性增添监听器 Listener

简介: 使用 TypeScript 自定义装饰器给类的属性增添监听器 Listener

语法

type PropertyDecorator =
  (target: Object, propertyKey: string | symbol) => void;

target:直接写在类的属性上?


看个例子:


function capitalizeFirstLetter(str: string) {
  return str.charAt(0).toUpperCase() + str.slice(1);
}
function observable(target: any, key: string): any {
  // prop -> onPropChange
  const targetKey = "on" + capitalizeFirstLetter(key) + "Change";
  target[targetKey] =
    function (fn: (prev: any, next: any) => void) {
      let prev = this[key];
      Reflect.defineProperty(this, key, {
        set(next) {
          fn(prev, next);
          prev = next;
        }
      })
    };
}
class C {
  @observable
  foo = -1;
  @observable
  bar = "bar";
}
const c = new C();
c.onFooChange((prev, next) => console.log(`prev: ${prev}, next: ${next}`))
c.onBarChange((prev, next) => console.log(`prev: ${prev}, next: ${next}`))
c.foo = 100; // -> prev: -1, next: 100
c.foo = -3.14; // -> prev: 100, next: -3.14
c.bar = "baz"; // -> prev: bar, next: baz
c.bar = "sing"; // -> prev: baz, next: sing

编译通不过:


image.png


一种解决办法是,添加下图这种 dummy 方法,这种方法不推荐,因为缺乏灵活性:

image.png



另一种方法较通用,即为类添加通用的所谓的 index signature:



image.png

语法如下:


意思是类 C 可以拥有任意的属性,且属性名称为 string

image.png


运行时,target 的类型为类 C 的构造函数:


image.png


key 为属性名:

image.png


在下图第 15 行代码,直接给 C 的构造函数注入一个新的 on 监听函数:


image.png


这个监听函数的函数体,直到代码44行 onXXX 被调用时才会被执行:


image.png


给 C 对象实例的 foo 属性使用 Reflect.defineProperty API 设置一个 set 方法。


image.png


这样,每次该实例的 foo 属性被修改时,就触发其 set 函数:


image.png



相关文章
|
6天前
|
JavaScript 前端开发 数据安全/隐私保护
TypeScript中装饰器的概念与使用场景
【4月更文挑战第23天】TypeScript的装饰器是特殊声明,用于附加到类的声明、方法、属性或参数,以修改行为。它们以`@expression`形式,其中`expression`是运行时调用的函数。装饰器应用场景包括:日志记录、调试、依赖注入、权限控制和AOP。通过装饰器,可以实现动态行为修改,如添加日志、注入依赖、控制权限以及事务管理。然而,应谨慎使用,避免过度复杂化代码。装饰器在现代 TypeScript 开发中扮演重要角色,帮助编写更健壮、可维护的代码。
|
6天前
|
JavaScript 前端开发 安全
ES6的类 vs TypeScript的类:解密两种语言中的面向对象之争
ES6的类 vs TypeScript的类:解密两种语言中的面向对象之争
|
6天前
|
JavaScript 编译器
TypeScript中泛型在函数和类中的应用
【4月更文挑战第23天】TypeScript的泛型在函数和类中提供了灵活性,允许处理多种数据类型。了解泛型是掌握TypeScript类型系统的关键。
|
6天前
|
编解码 JavaScript 前端开发
TypeScript【第三方声明文件、自定义声明文件、tsconfig.json文件简介、tsconfig.json 文件结构与配置】(六)-全面详解(学习总结---从入门到深化)
TypeScript【第三方声明文件、自定义声明文件、tsconfig.json文件简介、tsconfig.json 文件结构与配置】(六)-全面详解(学习总结---从入门到深化)
75 0
|
6天前
|
JavaScript
react+typescript通过window.xxx挂载属性报错的解决方案
react+typescript通过window.xxx挂载属性报错的解决方案
53 0
|
6天前
|
缓存 JavaScript 前端开发
【TypeScript技术专栏】TypeScript中的装饰器与元编程
【4月更文挑战第30天】TypeScript的装饰器是元编程工具,用于修改类、方法等行为。它们允许实现日志、权限控制、缓存等功能,支持类装饰器、方法装饰器等多种类型。装饰器借助JavaScript的Proxy和Reflection API实现,但过度使用可能造成复杂性。正确运用能提升代码质量,但需注意类型安全和维护性。
|
6天前
|
JavaScript 开发者 索引
【亮剑】探讨了在TypeScript中为对象动态添加属性的三种方式
【4月更文挑战第30天】本文探讨了在TypeScript中为对象动态添加属性的三种方式:1) 使用索引签名允许添加任意属性,如`[key: string]: any`;2) 通过接口和类型别名提供编译时类型检查,例如`interface Person { name: string; age: number; }`;3) 利用类创建具有属性的对象,如`class Person { name: string; age: number; }`。每种方法有其适用场景,开发者可根据需求选择。
|
6天前
|
JavaScript 安全 前端开发
【亮剑】TypeScript 由于其强类型的特性,直接为对象动态添加属性可能会遇到一些问题
【4月更文挑战第30天】本文探讨了在 TypeScript 中安全地为对象动态添加属性的方法。基础方法是使用索引签名,允许接受任何属性名但牺牲了部分类型检查。进阶方法是接口扩展,通过声明合并动态添加属性,保持类型安全但可能导致代码重复。高级方法利用 OOP 模式的类继承,确保类型安全但增加代码复杂性。选择哪种方法取决于应用场景、代码复杂性和类型安全性需求。
|
6天前
|
JavaScript
类和继承在TypeScript中的使用详解
【4月更文挑战第23天】TypeScript中的类和继承详解:使用`class`定义类,包含属性和方法,如`Animal`示例。通过`extends`实现继承,如`Dog`继承`Animal`,可重写父类方法。使用访问修饰符`public`、`protected`、`private`控制成员可见性。抽象类和抽象方法用于定义基类和强制子类实现特定方法,提升代码组织和可维护性。
|
6天前
react+typescript装饰器写法报错的解决办法
react+typescript装饰器写法报错的解决办法
24 1