TypeScript 第二个重要的里程碑是引入了装饰器(decorators)的功能。装饰器是一种特殊类型的声明,它可以被附加到类声明、方法、访问器、属性或参数上,来修改类的行为。在装饰器的引入之前,我们只能通过继承、混入和代理等方式来扩展现有的对象和类。而装饰器的引入,使得我们可以在编译阶段和运行时对类进行修改和增强,从而更好地实现代码复用和结构组织。
装饰器的语法很简洁,以 @
符号开头,后面跟着装饰器的名字和一对圆括号。装饰器可以接受参数,参数可以是任意类型的表达式,包括常量、变量、函数调用等。装饰器可以被放置在类声明、类属性、类方法、类方法参数上。
以下是一个使用装饰器的示例代码:
// 定义一个装饰器
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling method ${propertyKey} with arguments: ${args}`);
const result = originalMethod.apply(this, args);
console.log(`Method ${propertyKey} returned: ${result}`);
return result;
};
return descriptor;
}
class Calculator {
@log
add(a: number, b: number): number {
return a + b;
}
}
const calculator = new Calculator();
calculator.add(1, 2);
在上面的代码中,我们定义了一个名为 log
的装饰器,它用于打印方法的调用和返回值。装饰器被应用在 add
方法上,当我们调用 calculator.add(1, 2)
时,装饰器会先打印出方法的调用信息,然后调用原始的 add
方法,最后再打印出方法的返回值。
装饰器可以像扩展方法一样用于修改类的行为。我们可以通过装饰器来实现类似于切面编程的功能,例如日志记录、性能统计、授权验证等。装饰器也可以用于修改类的属性,例如添加属性的访问器和修改属性的默认值。
除了自定义装饰器,TypeScript 还提供了一些内置的装饰器,用于实现常见的功能,例如 @readonly
、@deprecated
、@observable
等。这些内置装饰器可以帮助我们更好地组织和管理代码。
下面是一个使用内置装饰器的示例代码:
class User {
@readonly
name: string;
constructor(name: string) {
this.name = name;
}
}
function readonly(target: any, propertyKey: string) {
Object.defineProperty(target, propertyKey, { writable: false });
}
const user = new User("Alice");
user.name = "Bob"; // Error: Cannot assign to 'name' because it is a read-only property.
在上面的代码中,我们使用了一个名为 readonly
的内置装饰器,它用于将 name
属性设置为只读。当我们尝试修改 user.name
的值时,由于 name
属性被设置为只读,所以会抛出一个错误。
综上所述,装饰器是 TypeScript 的一个重要特性,它为我们提供了一种方便的方式来修改和增强类的行为。使用装饰器,我们可以更好地实现代码复用和结构组织,同时也可以通过内置装饰器来实现一些常见的功能。装饰器的引入,使得 TypeScript 在面向对象编程方面的能力更加强大和灵活。
关系图
下面是一个示意性的关系图,展示了装饰器与类、方法、访问器、属性之间的关系:
erDiagram
class ||-down-|{ decorator }
class ||-down-|{ method }
class ||-down-|{ accessor }
class