在 TypeScript 中,裝飾器就是可以添加到類及其成員的函數(shù)。TypeScript 裝飾器可以注釋和修改類聲明、方法、屬性和訪問器。Decorator類型定義如下:
type Decorator = (target: Input, context: { kind: string; name: string | symbol; access: { get?(): unknown; set?(value: unknown): void; }; private?: boolean; static?: boolean; addInitializer?(initializer: () => void): void;}) => Output | void;上面的類型定義解釋如下:
接下來,我們就來了解一下裝飾器的各種類型。
當(dāng)將函數(shù)作為裝飾器附加到類時(shí),將收到類構(gòu)造函數(shù)作為第一個(gè)參數(shù):
type ClassDecorator = (value: Function, context: { kind: "class" name: string | undefined addInitializer(initializer: () => void): void}) => Function | void例如,假設(shè)想要使用裝飾器向 Rocket 類添加兩個(gè)屬性:fuel 和 isEmpty()。在這種情況下,可以編寫以下函數(shù):
function WithFuel(target: typeof Rocket, context): typeof Rocket { if (context.kind === "class") { return class extends target { fuel: number = 50 isEmpty(): boolean { return this.fuel == 0 } } }}在確保裝飾元素的類型確實(shí)是類之后,返回一個(gè)具有兩個(gè)附加屬性的新類。或者,可以使用原型對(duì)象來動(dòng)態(tài)添加新方法:
function WithFuel(target: typeof Rocket, context): typeof Rocket { if (context.kind === "class") { target.prototype.fuel = 50 target.prototype.isEmpty = (): boolean => { return this.fuel == 0 } }}可以按以下方式使用 WithFuel:
@WithFuelclass Rocket {}const rocket = new Rocket()console.log((rocket as any).fuel)console.log(`empty? ${(rocket as any).isEmpty()}`)/* Prints:50empty? false*/可以看到,這里將rocket轉(zhuǎn)換為any類型才能訪問新的屬性。這是因?yàn)檠b飾器無法影響類型的結(jié)構(gòu)。
如果原始類定義了一個(gè)稍后被裝飾的屬性,裝飾器會(huì)覆蓋原始值。例如,如果Rocket有一個(gè)具有不同值的fuel屬性,WithFuel裝飾器將會(huì)覆蓋該值:
function WithFuel(target: typeof Rocket, context): typeof Rocket { if (context.kind === "class") { return class extends target { fuel: number = 50 isEmpty(): boolean { return this.fuel == 0 } } }}@WithFuelclass Rocket { fuel: number = 75}const rocket = new Rocket()console.log((rocket as any).fuel)// 50方法裝飾器可以用于裝飾類方法。在這種情況下,裝飾器函數(shù)的類型如下:
type ClassMethodDecorator = (target: Function, context: { kind: "method" name: string | symbol access: { get(): unknown } static: boolean private: boolean addInitializer(initializer: () => void): void}) => Function | void如果希望在調(diào)用被裝飾的方法之前或之后執(zhí)行某些操作時(shí),就可以使用方法裝飾器。
例如,在開發(fā)過程中,記錄對(duì)特定方法的調(diào)用或在調(diào)用之前/之后驗(yàn)證前置/后置條件可能非常有用。此外,我們還可以影響方法的調(diào)用方式,例如通過延遲其執(zhí)行或限制在一定時(shí)間內(nèi)的調(diào)用次數(shù)。
最后,可以使用方法裝飾器將一個(gè)方法標(biāo)記為已廢棄,并記錄一條消息來警告用戶,并告知他們應(yīng)該使用哪個(gè)方法代替:
function deprecatedMethod(target: Function, context) { if (context.kind === "method") { return function (...args: any[]) { console.log(`${context.name} is deprecated and will be removed in a future version.`) return target.apply(this, args) } }}在這種情況下,deprecatedMethod函數(shù)的第一個(gè)參數(shù)是要裝飾的方法。確認(rèn)它確實(shí)是一個(gè)方法后(context.kind === "method"),返回一個(gè)新的函數(shù),該函數(shù)在調(diào)用實(shí)際方法之前包裝被裝飾的方法并記錄一條警告消息。
接下來,可以按照以下方式使用裝飾器:
@WithFuelclass Rocket { fuel: number = 75 @deprecatedMethod isReadyForLaunch(): Boolean { return !(this as any).isEmpty() }}const rocket = new Rocket()console.log(`Is ready for launch? ${rocket.isReadyForLaunch()}`)在isReadyForLaunch()方法中,引用了通過WithFuel裝飾器添加的isEmpty方法。注意,必須將其轉(zhuǎn)換為any類型的實(shí)例,與之前一樣。當(dāng)調(diào)用isReadyForLaunch()方法時(shí),會(huì)看到以下輸出,顯示警告消息被正確地打印出來:
isReadyForLaunch is deprecated and will be removed in a future version.Is the ready for launch? true屬性裝飾器與方法裝飾器的類型非常相似:
type ClassPropertyDecorator = (target: undefined, context: { kind: "field" name: string | symbol access: { get(): unknown, set(value: unknown): void } static: boolean private: boolean}) => (initialValue: unknown) => unknown | void屬性裝飾器的用例與方法裝飾器的用法也非常相似。例如,可以跟蹤對(duì)屬性的訪問或?qū)⑵錁?biāo)記為已棄用:
function deprecatedProperty(_: any, context) { if (context.kind === "field") { return function (initialValue: any) { console.log(`${context.name} is deprecated and will be removed in a future version.`) return initialValue } }}代碼與為方法定義的 deprecatedMethod 裝飾器非常相似,它的用法也是如此。
與方法裝飾器非常相似的是訪問器裝飾器,它是針對(duì) getter 和 setter 的裝飾器:
type ClassSetterDecorator = (target: Function, context: { kind: "setter" name: string | symbol access: { set(value: unknown): void } static: boolean private: boolean addInitializer(initializer: () => void): void}) => Function | voidtype ClassGetterDecorator = (value: Function, context: { kind: "getter" name: string | symbol access: { get(): unknown } static: boolean private: boolean addInitializer(initializer: () => void): void}) => Function | void訪問器裝飾器的定義與方法裝飾器的定義類似。例如,可以將 deprecatedMethod 和 deprecatedProperty 修飾合并到一個(gè)已棄用的函數(shù)中,該函數(shù)也支持 getter 和 setter:
function deprecated(target, context) { const kind = context.kind const msg = `${context.name} is deprecated and will be removed in a future version.` if (kind === "method" || kind === "getter" || kind === "setter") { return function (...args: any[]) { console.log(msg) return target.apply(this, args) } } else if (kind === "field") { return function (initialValue: any) { console.log(msg) return initialValue } }}上面介紹了裝飾器是什么以及如何正確使用它們,下面來看看裝飾器可以幫助我們解決的一些具體問題。
假設(shè)想要估計(jì)運(yùn)行一個(gè)函數(shù)需要多長時(shí)間,以此來衡量應(yīng)用的性能。可以創(chuàng)建一個(gè)裝飾器來計(jì)算方法的執(zhí)行時(shí)間并將其打印在控制臺(tái)上:
class Rocket { @measure launch() { console.log("3... 2... 1...
本文鏈接:http://m.www897cc.com/showinfo-26-5177-0.htmlTypeScript 裝飾器實(shí)用指南!
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com
上一篇: 六款開源、免費(fèi)的簡(jiǎn)歷制作神器,程序員必備!
下一篇: CSS 漸變中的顏色空間和色相插值