以下是Typescript官方文件中對decorator的定義
TypeScript Decorator 是一種特殊的宣告,可附加到class的宣告(declare)、方法(method)、訪問器(accessor)、屬性(property)或參數(parameter)。裝飾器使用
@expression的形式,其中expression必須能夠在運行時評估為一個函數,該函數將帶有有關被裝飾宣告的資訊被調用。
裝飾器的其他介紹可以參考這篇
由於decorator目前在typescript 5.0的版本仍然是實驗性功能,所以需要在 tsconfig.json 中加入以下的設定
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}在 TypeScript 中,你可以使用裝飾器來修改或擴充類別、方法或屬性。這裡用一個簡單的 Text 類別為例,我們可以創建一個裝飾器來記錄文字的長度:
function LogLength(target: any, key: string) {
let value = target[key];
const getter = () => {
console.log(`取得文字長度: ${value.length}`);
return value;
};
const setter = (next: string) => {
console.log(`設定新文字,長度為: ${next.length}`);
value = next;
};
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
class Text {
@LogLength
text: string = '';
}
const text = new Text(); // 設定新文字,長度為: 0
text.text = 'hello'; // 設定新文字,長度為: 5
console.log(text.text); // 取得文字長度: 5
在這個例子中,每次你取得或設定 Text 類別的 text 屬性時,都會記錄並輸出文字的長度。其中的 target :
target 是被裝飾類別的constructor。target 是類別的prototype。target 是類別的constructor(對於static member)或類別的prototype(對於instance member)。target 是類別的prototype。在上面的例子中由於我們的裝飾器是裝在 text 這個property 上,加上在底下我們有實例化它,所以拿到的target是 Text 這個 class 本身
而在裝飾器函數中,key 參數代表被裝飾的對象的名稱。如果裝飾器被附加到一個屬性上,那麼 key 就是該屬性的名稱;如果裝飾器被附加到一個方法上,那麼 key 就是該方法的名稱。因此,在上述例子中,我們的裝飾器是裝在 text 這個屬性上,所以 key 的值就是 'text'。
另外,decorator funciton 還可以接受第3個參數descriptor,descriptor 參數是一個物件,它描述了某個物件的屬性的特性。這個物件通常包含以下的一些或全部的屬性:
value: 屬性的值。writable: 如果該屬性的值可以被改變,則為 true。get: 一個函數,用作該屬性的 getter。set: 一個函數,用作該屬性的 setter。configurable: 如果該屬性的描述符可以被改變,或者該屬性可以從對應的物件上被移除,則為 true。enumerable: 如果該屬性出現在物件的枚舉屬性中,則為 true。我們也可以使用裝飾器工廠()來創建裝飾器。裝飾器工廠本質上是一個函數,它返回一個裝飾器。我們可以用它來傳遞參數給裝飾器。以下是一個如何使用裝飾器工廠來創建裝飾器的例子:
function Log(prefix: string) {
return function (target: any, key: string) {
let value = target[key];
const getter = () => {
console.log(`${prefix} - 取得文字長度: ${value.length}`);
return value;
};
const setter = (next: string) => {
console.log(`${prefix} - 設定新文字,長度為: ${next.length}`);
value = next;
};
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
};
}
class Text {
@Log('INFO')
text: string = '';
}
const text = new Text(); // INFO - 設定新文字,長度為: 0
text.text = 'hello'; // INFO - 設定新文字,長度為: 5
console.log(text.text); // INFO - 取得文字長度: 5
在這個例子中,我們的裝飾器工廠 Log 接受一個 prefix 參數,並返回一個裝飾器。這個裝飾器在每次取得或設定 text 屬性時,都會輸出帶有 prefix 的文字長度。