Typescript 中的泛型是什麼 - 為什麼使用它們,它們如何與程式碼示例一起使用

aow054發表於2024-09-21
介紹 什麼是泛型?typescript 中的泛型提供了一種建立可以使用多種型別而不是單一型別的元件的方法。它們允許您定義針對不同資料型別靈活且可重用的函式、類或介面,同時保持強大的型別安全性。本質上,泛型使您能夠編寫能夠適應不同型別的程式碼,而不會失去 typescript 型別系統的優勢。這種靈活性有助於構建健壯且可維護的程式碼,可以處理各種場景。 為什麼使用泛型?程式碼可重用性:泛型允許您編寫可以操作多種型別的函式、類或介面,而無需重複程式碼。您可以使用適用於任何型別的單個通用版本,而不是為每種型別建立單獨的函式版本。 function identity<t>(arg: t): t { return arg; } console.log(identity<string>("hello")); // works with strings console.log(identity<number>(42)); // works with numbers</number></string></t>登入後複製在這個例子中,恆等函式是通用的。它可以接受並返回任何型別 t,使其可重用於不同的資料型別。型別安全泛型確保您的程式碼在提供靈活性的同時保持型別安全。當您使用泛型時,typescript 會檢查傳遞給泛型元件的型別是否一致,從而減少出現執行時錯誤的可能性。 function wrapinarray<t>(value: t): t[] { return [value]; } const stringarray = wrapinarray("hello"); // typescript knows this is a string array const numberarray = wrapinarray(42); // typescript knows this is a number array</t>登入後複製這裡,wrapinarray 返回一個包含所提供值的陣列,typescript 確保陣列的型別與值型別一致。避免冗餘如果沒有泛型,您最終可能會編寫同一函式或類的多個版本來處理不同的型別。泛型消除了這種冗餘,從而產生更乾淨、更易於維護的程式碼。沒有泛型的示例: function logstring(value: string): void { console.log(value); } function lognumber(value: number): void { console.log(value); }登入後複製泛型示例: function logvalue<t>(value: t): void { console.log(value); } logvalue("hello"); // works with strings logvalue(42); // works with numbers</t>登入後複製使用泛型,logvalue 函式可以處理任何型別,從而減少為每種型別編寫單獨函式的需要。 泛型在 typescript 中如何工作 泛型的基本語法typescript 中的泛型使用佔位符語法,通常用 表示,其中 t 代表“型別”。這允許您定義可以對各種資料型別進行操作而不會失去型別安全性的函式、類或介面。function identity<t>(value: t): t { return value;}const stringidentity = identity("hello world");const numberidentity = identity(42);</t>登入後複製 通用函式泛型函式是可以處理多種型別而無需重複程式碼的函式。function wrapinarray<t>(value: t): t[] { return [value];}const stringarray = wrapinarray("hello");const numberarray = wrapinarray(123);</t>登入後複製在此示例中,wrapinarray 函式將任何值包裝在陣列中。 typescript 在呼叫函式時推斷型別,確保陣列包含正確的型別。 通用介面通用介面允許您定義可應用於不同型別的合約。示例:interface pair<t u> { first: t; second: u;}const nameagepair: pair<string number> = { first: "alice", second: 30,};</string></t>登入後複製 通用類泛型類對於建立可以儲存或管理任何型別資料的資料結構非常有用。示例:class box<t> { contents: t; constructor(value: t) { this.contents = value; } getcontents(): t { return this.contents; }}const stringbox = new box("gift");const numberbox = new box(100);</t>登入後複製說明:在此 box 類中,型別 t 允許該類儲存和檢索任何型別的資料。這種方法類似於您在現實生活中使用儲存容器的方式,其中容器的形狀(型別)可以根據其內容而變化。 通用約束有時,您想要限制泛型可以接受的型別。這就是通用約束的用武之地。function getproperty<t k extends keyof t>(obj: t, key: k) { return obj[key];}const car = { make: "toyota", year: 2022 };const make = getproperty(car, "make"); // validconst year = getproperty(car, "year"); // valid</t>登入後複製在此示例中,getproperty 函式確保您傳遞的鍵必須是物件的有效屬性。此約束透過強制金鑰存在於給定物件上來幫助防止錯誤。 泛型的常見用例 使用陣列和集合泛型在處理陣列或資料集合時特別有用,其中元素的型別可能會有所不同。function mergearrays<t>(arr1: t[], arr2: t[]): t[] { return arr1.concat(arr2);}const numbers = mergearrays([1, 2, 3], [4, 5, 6]);const strings = mergearrays(["a", "b", "c"], ["d", "e", "f"]);</t>登入後複製在此示例中,mergearrays 函式使用泛型型別 t 來合併任意型別的兩個陣列。無論陣列包含數字、字串還是任何其他型別,該函式都能無縫處理它們。將其想象為組合兩盒物品(例如水果或工具)。盒子內的物品型別可能有所不同,但組合它們的過程保持不變。 api響應處理處理api響應時,不同端點返回的資料結構可能會有所不同。泛型可以透過建立適用於各種型別的靈活函式來簡化對這些響應的處理。interface apiresponse<t> { status: number; data: t; message?: string;}function handleapiresponse<t>(response: apiresponse<t>): t { if (response.status === 200) { return response.data; } else { throw new error(response.message || "api error"); }}const userresponse = handleapiresponse({ status: 200, data: { name: "john", age: 30 },});const productresponse = handleapiresponse({ status: 200, data: { id: 1, name: "laptop" },});</t></t></t>登入後複製在此示例中,handleapiresponse 函式適用於任何型別的 api 響應,無論是使用者資料、產品詳細資訊還是其他內容。泛型型別 t 確保函式根據響應返回正確型別的資料。想象一下在您家門口收到不同的包裹(api 響應)。內容可能有所不同(例如雜貨、電子產品),但您有一種方法可以根據裡面的內容正確開啟每件商品的包裝。 實用程式型別typescript 提供了多種實用程式型別,它們在底層使用泛型來執行常見的型別轉換。這些實用程式型別對於塑造和控制程式碼中的型別非常有用。示例:partial:使 t 中的所有屬性可選。interface user { name: string; age: number; email: string;}const updateuser: partial<user> = { email: "newemail@example.com",};</user>登入後複製readonly:使 t 中的所有屬性只讀。const user: readonly<user> = { name: "john", age: 30, email: "john@example.com",};// user.age = 31; // error: cannot assign to 'age' because it is a read-only property.</user>登入後複製 record:構造一個屬性鍵為k、屬性值為t的物件型別。 const rolepermissions: record<string string> = { admin: ["create", "edit", "delete"], user: ["view", "comment"],};</string>登入後複製這些實用程式型別(部分、只讀、記錄)是使用泛型構建的,以提供靈活且可重用的型別轉換。它們有助於更新物件的某些部分、確保不變性或在 typescript 中建立字典/對映等場景。 泛型高階主題 多種型別引數typescript 允許在函式或類中使用多個型別引數,從而實現更大的靈活性並控制不同型別在程式碼中的互動方式。function mergeobjects<t u>(obj1: t, obj2: u): t &amp; u { return { ...obj1, ...obj2 };}const person = { name: "alice" };const contact = { email: "alice@example.com" };const merged = mergeobjects(person, contact);// merged is of type { name: string } &amp; { email: string }</t>登入後複製在此示例中,mergeobjects 函式使用兩個泛型型別引數 t 和 u 來合併兩個物件。生成的物件結合了兩個輸入物件的屬性,並使用 typescript 確保為合併結果推斷出正確的型別 預設通用型別typescript 還允許您定義泛型引數的預設型別。如果沒有明確提供,此功能會提供後備型別,從而簡化程式碼中泛型的使用。function createpair<t string>(value1: t, value2: t): [t, t] { return [value1, value2];}const stringpair = createpair("hello", "world"); // defaults to [string, string]const numberpair = createpair<number>(10, 20); // explicitly set to [number, number]</number></t>登入後複製createpair 函式的泛型型別 t 有一個預設的字串型別。如果未指定型別,typescript 將使用字串,但您可以在必要時透過提供不同的型別來覆蓋它。 使用泛型進行型別推斷typescript 能夠根據函式或類的使用方式推斷泛型的型別。這減少了顯式指定型別的需要,使程式碼更加簡潔且更易於使用。function wrapinarray<t>(value: t): t[] { return [value];}const numberarray = wrapinarray(42); // typescript infers t as numberconst stringarray = wrapinarray("hello"); // typescript infers t as string</t>登入後複製說明:在wrapinarray函式中,typescript根據傳遞給函式的引數型別自動推斷t的型別。這種推斷型別的能力使泛型更加強大且易於使用,因為它通常消除了對顯式型別註釋的需要。 常見陷阱和最佳實踐 過度使用泛型雖然泛型是一個強大的功能,但它們有時可能會被過度使用,導致程式碼不必要地複雜且難以理解。function overlygenericfunction<t u>(param1: t, param2: u): [t, u] { return [param1, param2];}</t>登入後複製在此示例中,該函式是通用的,但如果邏輯實際上並不依賴於它們是不同的型別,則可能不需要使用兩個型別引數。這會使程式碼更難閱讀和維護。最佳實踐:當泛型提供明顯的好處時,例如當型別真正靈活且多樣時,請使用泛型。如果特定型別或簡單的聯合型別也能完成這項工作,那麼通常最好使用它們。 平衡靈活性和複雜性泛型提供了靈活性,但平衡靈活性和簡單性至關重要。使用泛型使程式碼過於複雜可能會使其更難以理解和維護。溫馨提示:使用泛型實現可重用性:如果您發現自己為多種型別編寫相同的邏輯,泛型可以幫助使程式碼可重用。在適當的時候堅持使用特定型別:如果一個函式或類只適用於特定型別,那麼使用該特定型別通常比使用通用型別更清晰。保持簡單:當簡單的解決方案就足夠時,避免引入泛型。增加的複雜性應該由靈活性的需要來證明。 避免任何在 typescript 中使用 any 會很快破壞該語言提供的型別安全性。泛型提供了一種更安全的替代方案,使您能夠保持靈活性,同時仍然受益於 typescript 的型別系統。function logValue(value: any): void { console.log(value);}function logGenericValue<t>(value: T): void { console.log(value);}</t>登入後複製在第一個函式中,使用 any 意味著 typescript 不會檢查值的型別,可能會導致執行時錯誤。相比之下,第二個函式使用泛型型別 t,在保持型別安全的同時仍然靈活。最佳實踐:只要需要靈活性,就優先選擇泛型。這種方法可確保 typescript 繼續強制執行型別安全,降低錯誤風險,並使您的程式碼更可預測且更易於除錯。 結論typescript 中的泛型是建立可重用、靈活且型別安全的程式碼的強大工具。它們允許您編寫可與多種型別一起使用的函式、類和介面,從而減少冗餘並增強程式碼可維護性。透過使用泛型,您可以避免任何陷阱,保持程式碼型別安全,並保持清晰和簡單。泛型在 typescript 中開闢了一個充滿可能性的世界,使編寫適應性強且可重用的程式碼變得更加容易。我鼓勵您探索如何在您的專案中應用泛型。無論您是處理 api 響應、使用集合還是建立實用函式,泛型都可以顯著提高程式碼的靈活性和健壯性。 以上就是Typescript 中的泛型是什麼 - 為什麼使用它們,它們如何與程式碼示例一起使用的詳細內容,更多請關注我的其它相關文章!

相關文章