【译】TypeScript装饰器:完整指南

avatar

原文地址:deadsimplechat.com/blog/typesc…

装饰器是很棒的特性,很多库都是由装饰器组成的,比如react和angular。这是一个很棒的概念

在本文中,我们将学习typescript装饰器。

什么是TypeScript装饰器?

装饰器基本上就是核心的函数。

通过装饰器,你可以将可重用的行为应用到类、方法和属性中。装饰器的灵感来自Java和Python等其他语言中的装饰器

Dead Simple Chat提供Javascript聊天API和SDK,可以在几分钟内将应用内聊天添加到React应用程序中。Dead Simple Chat是一个高度可定制的聊天解决方案,可以用于任何聊天用例。

装饰师的类型

这些装饰师可以应用于

  1. Class
  2. Method
  3. Class Property
  4. Accessor and
  5. Method Parameter
  1. Class decorator

类装饰器应用于类的构造函数,可用于观察、修改和更改类定义

一个类装饰器的例子

type ClassDecorator = <TFunction extends Function>
  (target: TFunction) => TFunction | void;
  • @Params
  1. 目标类的构造函数

@Returns

如果装饰器返回一个值。它取代了类定义,并且是用新的属性和方法扩展类定义的一种方式

让我们通过一个例子来看看这个问题

function TechClass(constructor: Function) {
    console.log(`Class Name: ${constructor.name}`);
  }
  
  @TechClass
  class CoolClass {
    constructor() {
      console.log('New Class instance has beed created');
    }
  }

新类实例

在这里,TechClass是一个类装饰器,当它被创建时,装饰器被触发,并且类名CoolClass被记录到控制台

2. Method Decorators

方法装饰器用于方法,它们可以更改和替换或观察函数定义

让我们用一个例子来学习更多关于方法装饰器的知识:

function Techfunc(target: any, propertyName: string, descriptor: PropertyDescriptor) {
  const realMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`function Name: ${propertyName}`);
    return realMethod.apply(this, args);
  };
}

class CoolClass {
  @Techfunc
  testFunc() {
    console.log('from testFunc');
  }
}

const instance = new CoolClass();
instance.testFunc();

方法修饰符

这里,techfunction装饰器将函数名记录到控制台。CoolClass的TestFunc方法触发TechFunc装饰器,然后将函数名记录到控制台

让我们看另一个例子

function CoolLogs(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;

  descriptor.value = function (...args) {
    console.log('params: ', ...args);
    const result = original.call(this, ...args);
    console.log('const result: ', result);
    return result;
  }
}

class C {
  @CoolLogs
  add(a: number, b:number ) {
    return a + b;
  }
}

const c = new C();
c.add(1, 2);
// -> params: 1, 2
// -> result: 3

方法decorator的例子

这里我们有一个CoolLogs函数,作为类c的装饰器

我们的装饰器有3个参数

  • target
  • propertyKey
  • descriptor

在const original中存储函数的原始值。

然后,原始函数被另一个接受多个参数的函数所取代

然后用相同的参数调用新函数

属性修饰符

属性描述符可用于更改或观察属性的属性定义

Dead Simple Chat提供Javascript聊天API和SDK,可以在几分钟内将应用内聊天添加到React应用程序中。Dead Simple Chat是一个高度可定制的聊天解决方案,可以用于任何聊天用例。

例如

function TestParameter(target: any, propertyName: string, CoolParameter: number) {
  console.log(`Cool Parameter: ${CoolParameter}`);
}

class SomeClass {
  exampleMethod(@TestParameter saySomething: string) {
    console.log(`from exampleMethod: ${saySomething}`);
  }
}

const instance = new SomeClass();
instance.exampleMethod('Hello');

属性修饰符

这里TestProperty定义了TestProperty装饰器,它观察一个string类型的ClassProperty

每当创建新的类实例时,Test属性都会将该属性的名称记录到控制台

参数装饰

参数装饰器用于监视和更改函数或方法参数

让我们用一个例子来看看参数装饰器

function TestParameter(target: any, propertyName: string, CoolParameter: number) {
  console.log(`Cool Parameter: ${CoolParameter}`);
}

class SomeClass {
  exampleMethod(@TestParameter saySomething: string) {
    console.log(`from exampleMethod: ${saySomething}`);
  }
}

const instance = new SomeClass();
instance.exampleMethod('Hello');

参数装饰器的例子

这里我们有一个函数TestParameter。记录CoolParameter参数

然后我们有一个带有一个名为exampleemethod的方法的SomeClass。当调用exampleMethod时,decorator被触发,TestParameter函数被调用,然后将CoolParameter记录到控制台

访问修饰符

访问器装饰器类似于方法装饰器,但唯一的区别是方法装饰器在其描述符中有键

  • Value
  • writable
  • configurable
  • enumerable

Accessor装饰器中的描述符有键

  • get
  • set
  • enumerable
  • configurable

访问器装饰器接受以下三个参数

  1. Constructor function or target prototype(构造函数或目标原型)
  2. property name(属性名称)
  3. property descriptor(属性描述符)

Dead Simple Chat提供Javascript聊天API和SDK,可以在几分钟内将应用内聊天添加到React应用程序中。Dead Simple Chat是一个高度可定制的聊天解决方案,可以用于任何聊天用例。

何时使用装饰器

  1. Before/After Hooks(前/后钩子函数)
  2. Watch property changes and method calls.(监听属性变化和方法调用。)
  3. Transform parameters(转换参数)
  4. Add extra method or properties(添加额外的方法或属性)
  5. Runtime type validation(运行时类型验证)
  6. Auto serialization and deserialization(自动序列化和反序列化)
  7. Dependency Injection(依赖注入)

1. Before /After Hooks

Before / After钩子意味着在函数被调用之前和之后调用装饰器,这在调试、记录和测量性能方面非常有用

让我们通过一个例子来研究它

function ExampleOfBeforeAfterHookFunction(target: any, propertyName: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Before: ${propertyName}`);
    const result = originalMethod.apply(this, args);
    console.log(`After: ${propertyName}`);
    return result;
  };
}

class SomeClass {
  @ExampleOfBeforeAfterHookFunction
  coolFunction() {
    console.log('Inside coolFunction');
  }
}

const instance = new SomeClass();
instance.coolFunction();

前/后钩子的例子

这里我们有ExampleOfBeforeAfterHookFunction函数

我们在哪里存储originalMethod在originalMethod const

然后我们用一个新的函数实现替换原来的方法,这个函数实现使用…参数属性

然后我们记录属性名之前的内容然后我们调用originalMethod函数然后我们记录属性名之后的内容。

这就是实现before / after钩子方法的方法

2. 注意属性更改和方法调用。

Watch是一个属性装饰器,它记录属性以及被装饰方法的方法调用

这在调试和性能监视时特别有用。

让我们通过一个例子来了解更多关于Watch属性以及它是如何工作的

function see(target: any, propertyName: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`function has been called: ${propertyName} with args:`, args);
    return originalMethod.apply(this, args);
  };
}

class SomeClass {
  myProperty: string;

  @see
  setProperty(value: string) {
    console.log('Set the value to ');
    this.myProperty = value;
  }
}

const instance = new SomeClass();
instance.setProperty('Awesome Great work Done');

看属性

3.变换参数

在转换参数函数中,在调用方法之前将转换函数应用于特定参数

让我们通过一个例子来学习更多关于变换参数的知识

function CoolFunc(SomeFunc: (arg: any) => any): ParameterDecorator {return (target: any, propertyKey: any, parameterIndex:any) => {const originalMethod = target[propertyKey];target[propertyKey] = function()args: any[]) {args[parameterIndex] = SomeFunc(args[parameterIndex]);originalMethod返回。应用(这个,args);};};}类MyClass {myMethod(@CoolFunc((x) => x * 2) num: number) {console.log('转换参数:${num} ');}} const instance = new MyClass();instance.myMethod (5);

看属性

这里发生了什么

方法装饰器see会记录被装饰方法的名称和参数

当方法see在MyClass的实例中被调用时,它会记录方法名,并设置myproperty的属性值

4. 添加额外的方法或属性

您可以使用装饰器添加一个额外的方法或属性。下面是如何使用一个示例来实现这一点

function AddMethod(){返回函数(constructor: function) {constructor.prototype.AddMethod = function () {console.log('通过decorator为属性添加了一个新方法');};};} @AddMethod()类someeclass {} const实例=新的someeclass ();(instance as any).AddMethod();

使用decorator添加额外的方法或属性

代码中有一个名为AddMethod的函数,它为装饰类的原型添加了一个函数,在本例中是SomeClass

当调用SomeClass的实例时,可以在其上调用addMethod。add方法将一条消息记录到控制台

5. 运行时类型验证

运行时类型验证确保在运行时函数中使用的参数和变量以及const和数据的值的类型与预期类型的值匹配

与静态类型验证发生在软件编译期间不同,运行时类型验证发生在函数或程序运行时,因此它有助于验证外部输入数据

让我们用一个例子来学习更多关于运行时类型验证的知识

function SomeFunc(target: any, propertyKey: string, parameterIndex: number) {const originalMethod = target[propertyKey];target[propertyKey] = function()args: any[]) {if (typeof args[parameterIndex] !== 'number'){抛出新的错误('发生错误${parameterIndex} ');}返回originalMethod。应用(这个,args);};}类TestClass {calculateArea(@SomeFunc半径:数字){返回数学。PI *半径*半径;}} const instance = new TestClass();尝试{instance。calculateArea('这是NaN');} catch (error) {console.error(error.message);} console.log (instance.calculateArea (6));

运行时类型验证示例

6. 自动序列化和反序列化

自动序列化和反序列化指的是从一种数据类型转换为另一种数据类型反序列化的实践,以便以特定格式存储数据

然后,为了呈现数据或其他功能,再次从一种数据类型转换为原始数据类型可以使用数据

下面是一个示例,解释如何使用装饰器来完成此操作

function SerializeFunc(constructor: function) {constructor.prototype.serialize = function(){返回JSON.stringify(this);};constructor.deserialize = function (json: string){返回新的构造函数(json .parse(json));};}函数DeserializeFunc(目标:any, propertyKey: string,描述符:PropertyDescriptor) {const originalMethod = descriptor.value;描述符。value = function (serializedData: string) {const deserializedData = JSON.parse(serializedData);originalMethod返回。应用(这个,deserializedData);};} @SerializeFunc类Person{构造函数(公共名称:字符串,公共年龄:数字){}@SerializeFunc greet(数据:{名称:字符串;真棒,人们叫我${data.name},我的年龄是${data。年龄1岁。}} const man = new man ('Jim Class'43);const serializedMan = man.serialize();console.log (serializedMan);// {"name":"Jim Class""age":43} const deserializedMan = (Man as any).deserialize(serializedMan);console.log (deserializedMan.greet ());const serializedData = '{"name":"Don markell","age":56}';console.log (man.greet (serializedData));

自动序列化和反序列化

7. 依赖注入

装饰器也可以用于依赖注入。依赖注入是将方法所依赖的函数和对象作为参数提供给它的做法

这有助于解耦代码并使其更简洁

decorator通过提供一种直接将依赖项注入类构造函数而不更改类实现的方法来帮助进行依赖注入

这使得它们更容易维护和测试

Dead Simple Chat提供Javascript聊天API和SDK,可以在几分钟内将应用内聊天添加到React应用程序中。Dead Simple Chat是一个高度可定制的聊天解决方案,可以用于任何聊天用例。

使用装饰师的优点

  1. 横切关注点

当一个节目的部分转播到该节目的许多其他部分时。就像一个程序可能依赖于其他类的方法或属性一样,这可能是装饰器的一个用例,它们提供了一种维护代码的简单方法,并提供了改进的可读性

2. 依赖注入

依赖注入是一种软件设计模式,依赖于其他对象或函数的对象或函数接收依赖注入

这类似于控制反转,导致松散耦合的程序和模块化的代码库

这里也可以在装饰中派上用场

3.验证

装饰器可用于验证对象的输入或状态。

4. 代码组织

不属于main函数或逻辑的代码可以使用修饰符进行封装,从而使代码更具可读性和可维护性

Dead Simple Chat提供Javascript聊天API和SDK,可以在几分钟内将应用内聊天添加到React应用程序中。Dead Simple Chat是一个高度可定制的聊天解决方案,可以用于任何聊天用例。

结论

在本文中,我们学习了如何使用typescript装饰器,我们还使用了一些示例来使它们更容易理解

我希望这篇文章对你有用

谢谢你阅读这篇文章