装饰器
装饰器本身是一个函数 装饰器通过@符号来使用
需要开启tsconfig.json
中的experimentalDecorators: true
执行顺序
在TypeScript里,当多个装饰器应用在一个声明上时会进行如下步骤的操作:
由上至下依次对装饰器表达式求值。 求值的结果会被当作函数,由下至上依次调用。
类的装饰器
参数
类装饰器接受的参数是类的构造函数
使用
- 基本使用
ts
function logDocorator(constructor: any) {
constructor.prototype.logger = function () {
// 输出日期
console.log(this.name)
console.log(new Date().toLocaleString());
}
}
@logDocorator
class Person {
constructor(public name: string) {
}
}
let person: any = new Person('zhangsan');
person.logger();
- 装饰器传参
装饰器工厂函数
ts
function logDocorator(log: boolean) {
return function (constructor: any) {
constructor.prototype.logger = function () {
// 输出日期
console.log(this.name)
if (log) {
console.log(new Date().toLocaleString());
}
}
}
}
@logDocorator(false)
class Person {
constructor(public name: string) {
}
}
let person: any = new Person('zhangsan');
person.logger();
ts类型报错修复
ts
// 1.构造函数使用泛型
function logDocorator<T extends new (...args: any[]) => any>(log: boolean) {
return function (constructor: T) {
return class extends constructor {
name = `new name`
logger() {
// 输出日期
console.log(this.name)
if (log) {
console.log(new Date().toLocaleString());
}
}
}
}
}
// 2.class使用装饰器修饰过的class
const Person = logDocorator(true)(class {
constructor(public name: string) {
}
})
let person = new Person('zhangsan');
person.logger()
方法装饰器
参数
对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。 方法名。 成员的属性描述符。
使用
- 修改descriptor
ts
descriptor.writable = writable
- 修改原始函数
ts
descriptor.value = function () {
console.log(new Date().toLocaleString())
}
code
ts
/**
* @param value
*/
function functionDecorator(value: boolean) {
/**
* @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
* @param key 成员的名字
* @param descriptor 成员的属性描述符
*/
return function (target: any, key: string, descriptor: PropertyDescriptor) {
console.log(target, key, descriptor)
// 1.修改descriptor
descriptor.writable = value
// 2.修改原始函数
descriptor.value = function () {
console.log(new Date().toLocaleString())
}
}
}
class Person {
constructor(public name: string) {
}
@functionDecorator(false)
say() {
console.log(this.name)
}
}
let person = new Person('zhangsan');
// 此时代码报错,无法修改
person.say = function () {
console.log(new Date().toLocaleString())
}
person.say()
访问器装饰器
访问器装饰器是 TypeScript 中一种特殊的装饰器,用于装饰类的属性访问器(getter 和 setter)。
它允许你在访问器被定义时对其进行修饰,以实现各种功能,比如添加日志、权限检查等。
参数同方法装饰器
code
ts
type SetterFunction<T> = (this: T, value?: any) => void;
function visitDecorator() {
/**
* @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
* @param key 成员的名字
* @param descriptor 成员的属性描述符
*/
return function (target: any, key: string, descriptor: PropertyDescriptor) {
console.log(target, key, descriptor);
/**
* descriptor
* {
"enumerable": false,
"configurable": true
}
*/
const originalGetter: SetterFunction<any> | undefined = descriptor.get;
const originalSetter: SetterFunction<any> | undefined = descriptor.set;
// 重写getter方法
descriptor.get = function () {
console.log(`Getting value of property ${key}`);
return originalGetter?.call(this); // 保留原始getter方法的行为
};
// 重写setter方法
descriptor.set = function <T>(value: T) {
console.log(`Setting value of property ${key} to ${value}`);
originalSetter?.call(this, value); // 保留原始setter方法的行为
};
};
}
class Person {
private _name: string;
constructor(name: string) {
this._name = name;
}
get name() {
return this._name;
}
@visitDecorator()
set name(name: string) {
this._name = name;
}
}
const person = new Person('zhangsan');
console.log(person.name); // 输出: zhangsan
person.name = 'new name'; // 设置成功
console.log(person.name); // 输出: new name
注意
在访问器装饰器中,descriptor 参数是一个包含 get 和 set 方法的对象。虽然 TypeScript 允许你访问 descriptor.writable 属性,但这个属性只在数据属性(即普通的成员属性,而非访问器属性)中有效,对于访问器属性来说,并没有 writable 这个属性。
属性装饰器
参数
target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
key 属性名
使用
ts
function nameDecorator() {
/**
* @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
* @param key 成员的名字
*/
return function (target: any, key: string): any {
console.log(target, key);
// 替换原有的属性描述符
const descriptor: PropertyDescriptor = {
writable: false,
}
return descriptor
};
}
class Person {
@nameDecorator()
public name = 'www'
}
const person = new Person();
console.log(person.name); // 输出: zhangsan
// 报错,不可修改 Uncaught (in promise) TypeError: Cannot assign to read only property 'name' of object '#<Person>'
person.name = 'new name'; // 设置成功
console.log(person.name); // 输出: new name
参数装饰器
参数
target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。 key 方法名 paramIndex 参数的索引
使用
ts
function paramDecorator() {
/**
* @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
* @param key 成员的名字
* @param paramIndex 参数的索引
*/
return function (target: any, key: string, paramIndex: number): any {
console.log(target, key, paramIndex);
};
}
class Person {
getInfo(name: string, @paramDecorator() age: number) {
console.log(name, age)
}
}
const person = new Person();
person.getInfo('www', 18)
装饰器的应用
异常处理
ts
function exceptionDecorator(name: string) {
return function (target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
try {
originalMethod.apply(this, args);
console.log(`${name} is success`);
return;
}
catch (error) {
console.log(`${name} is error`, error);
}
}
}
}
class Person {
@exceptionDecorator('getInfo')
getInfo(name: string, age: number) {
}
@exceptionDecorator('getName')
getName(name: string) {
throw new Error('null');
}
}
const person = new Person();
person.getInfo('www', 18)
person.getName('www')