當前位置: 妍妍網 > 碼農

TypeScript進階指南:泛型和裝飾器的妙用

2024-02-16碼農

TypeScript進階指南:泛型和裝飾器的妙用

TypeScript作為JavaScript的超集,為大型套用的開發提供了強大的工具和概念,使得程式碼更加健壯和可維護。在TypeScript的眾多高級特性中,泛型和裝飾器是兩個極其強大的工具。它們能夠提高程式碼的復用性,同時為復雜的問題提供清晰、型別安全的解決方案。在這篇進階指南中,我將深入探討泛型和裝飾器的高級用法,並透過具體的程式碼範例來展現它們如何提升我們程式碼的品質。

泛型的妙用

泛型是TypeScript中實作程式碼復用的一個重要工具。它允許我們編寫可適用於多種型別的元件,而不必犧牲型別的安全性。

基礎概念

泛型可以被認為是型別的變量,它可以捕獲傳遞給元件的型別資訊,並在整個元件中使用這些資訊。

function identity<T>(arg: T): T {
return arg;}

在這個 identity 函式中, T 是一個型別變量,它捕獲了使用者提供的型別(即傳遞給 identity 的參數的型別)。這樣,這個函式就可以返回幾乎任何型別的輸入,同時保持型別資訊。

高級用法:約束泛型

我們不僅可以定義泛型,還可以對泛型施加約束,以限制泛型可以表示的型別。

interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;}

在這個例子中,我們定義了一個 Lengthwise 介面,它有一個單獨的 .length 內容。然後我們說,泛型 T 必須符合 Lengthwise 的形狀,這意味著傳遞給 loggingIdentity 的參數必須有 .length 內容。

使用泛型的實際案例

假設我們正在編寫一個前端應用程式,需要從伺服器獲取不同型別的資源。我們可以編寫一個泛型函式,來處理對不同資源的GET請求。

async function getResource<T>(url: string): Promise<T> {
let response = await fetch(url);
let body = await response.json();
return body as T;
}
// 使用
interface User {
name: string;
email: string;
}
async function getUser(userId: string) {
const user = await getResource<User>(`/api/users/${userId}`);
console.log(user.name);}

在這個 getResource 函式中,我們使用了泛型 T 來捕獲響應體的型別,這樣我們就可以根據不同的呼叫安全地推斷出返回型別。

裝飾器的妙用

裝飾器是TypeScript中用來修改類、方法、存取器、內容或參數的聲明的特殊型別的聲明。裝飾器使用 @expression 這樣的形式, expression 求值後必須為一個函式,它會在執行時被呼叫。

類裝飾器

類裝飾器在類別宣告之前被聲明(緊靠著類別宣告)。類裝飾器套用於類建構函式,可以用來監視、修改或替換類別定義。

function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}}

在這個例子中, sealed 裝飾器會封閉 Greeter 類,阻止添加新的內容,並且在例項化時標記為不可配置。

方法裝飾器

方法裝飾器聲明在一個方法的聲明之前(緊靠著方法聲明)。它會被套用到方法的內容描述符上,可以用來監視、修改或替換方法定義。

function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}}

在這個例子中, enumerable 裝飾器修改了 greet 方法的列舉性。當我們設定為 false 時,這個方法就不會出現在類的列舉內容中。

裝飾器工廠

如果我們想自訂裝飾器如何套用到一個聲明上,我們可以寫一個裝飾器工廠函式。裝飾器工廠是一個簡單的函式,它返回表達我們裝飾器在執行時呼叫方式的函式。

function format(formatString: string) {
return function (target: any, propertyKey: string) {
let value: string;
const getter = function () {
return formatString.replace("%s", value);
};
const setter = function (newVal: string) {
value = newVal;
};
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
};
}
class Greeter {
@format("Hello, %s")
greeting: string;
constructor(message: string) {
this.greeting = message;
}}

在這個例子中, format 裝飾器工廠允許我們將一個字串樣版套用於 Greeter 類的 greeting 內容。每次存取這個內容時,都會返回一個格式化後的字串。

結論

泛型和裝飾器是TypeScript提供的強大工具,它們能夠極大地提高我們程式碼的復用性和可維護性。透過泛型,我們可以編寫出適用於多種型別的通用元件,而裝飾器則允許我們以聲明性的方式修改和增強類和類成員的行為。掌握了這些高級特性,我們就可以編寫出更加靈活和健壯的TypeScript程式碼。

如果喜歡我的內容,不妨點贊關註,我們下次再見!

大家註意:因為微信最近又改了推播機制,經常有小夥伴說錯過了之前被刪的文章,或者一些限時福利,錯過了就是錯過了。所以建議大家加個 星標 ,就能第一時間收到推播。

點個喜歡支持我吧,點個 在看 就更好了