大家好,我是王天~
這篇文章是 ts入門指南系列中第四篇,主要講解ts中的泛型應用,泛型在ts中是比較重要的概念,我花挺長時間才搞明白的,希望能幫助到大家 ~
** ts 入門指南系列 **
- Ts和Js 誰更適合前端開發?| typescript 入門指南 01
- 詳解tsconfig.json 配置檔案 | 02 ts入門指南
- ts基礎使用-語法型別 | typescript入門指南 03
1. 前言
我們可以把泛型比喻為一個型別佔位符,它告訴編譯器:“嘿,這裡有一個型別引數,我現在不確定具體是什麼型別,但稍後會告訴你。”
透過使用泛型,我們可以編寫更靈活、更可複用的程式碼。它允許我們在定義函式、類或介面時使用型別佔位符來表示型別,而不直接指定具體的型別。這樣,在實際使用時,我們可以傳入不同的型別引數,使得程式碼可以適用於多種情況。
例如,讓我們看一個簡單的例子,來解釋泛型的使用。假設我們有一個名為 identity
的函式,它接受一個引數並返回該引數:
function identity<T>(value: T): T {
return value;
}
圖片來源網路
在上述程式碼中,<T>
表示這是一個泛型函式,T
是一個型別引數,可以是任何型別。函式的引數 arg
的型別為 T
,返回值的型別也是 T
。
這樣,我們可以在函式呼叫時傳入不同的型別引數,使得函式適用於各種型別的引數。
例如,我們可以這樣呼叫 identity
函式:
let result1 = identity<number>(42); // 傳入 number 型別
let result2 = identity<string>("Hello, TypeScript"); // 傳入 string 型別
在第一次呼叫時,型別引數 number
被傳遞給 identity
函式,所以返回值的型別也是 number
。而在第二次呼叫時,型別引數 string
被傳遞給 identity
函式,所以返回值的型別是 string
。
透過使用泛型,我們可以編寫出更加通用的函式,不限於特定的型別。這樣一來,我們能夠避免程式碼的重複編寫,提高程式碼的可複用性和靈活性。
泛型主要用在四個場合:函式、介面、類和別名。
基本使用
泛型使用尖括號 <T>
來表示,並在定義函式、類或介面時指定型別引數。下面是一些基本的使用示例:
// 示例1: 建立一個泛型函式
function identity<T>(arg: T): T {
return arg;
}
// 示例2: 使用泛型函式
let output = identity<string>("Hello");
console.log(output); // 輸出: Hello
// 示例3: 使用型別推斷,自動推斷泛型型別
let output2 = identity("Hello");
console.log(output2); // 輸出: Hello
在示例 1 中,函式 identity
使用了泛型型別引數 T
,表示引數和返回值的型別可以是任何型別。示例 2 和示例 3 展示瞭如何使用泛型函式並指定引數的型別。
。
2. 使用泛型變數:
泛型變數允許我們在函式或類中使用一種不確定的型別,而在實際使用時才確定具體的型別。
舉個例子,考慮一個簡單的函式identity
,它接受一個引數並返回相同的值:
function identity<T>(arg: T): T {
return arg;
}
在這個例子中,我們使用了泛型變數T
,它可以代表任意型別。當我們呼叫函式identity
時,編譯器會根據傳入的引數型別自動推斷T
的具體型別。
例如:
let result = identity<string>("Hello");
console.log(result); // 輸出:Hello
let value = identity<number>(42);
console.log(value); // 輸出:42
透過使用泛型變數,函式identity
可以適用於不同型別的引數,提供了更高的靈活性和可重用性。
3. 泛型型別:
泛型型別允許我們建立可以適用於不同型別的變數、函式或類。
舉個例子,考慮一個簡單的陣列反轉函式reverse
:
function reverse<T>(array: T[]): T[] {
return array.reverse();
}
在這個例子中,我們定義了一個泛型函式reverse
,接受一個陣列引數,並返回反轉後的陣列。泛型型別T
用於指定陣列的元素型別。
例如:
let numbers: number[] = [1, 2, 3, 4, 5];
let reversedNumbers = reverse(numbers);
console.log(reversedNumbers); // 輸出:[5, 4, 3, 2, 1]
let strings: string[] = ["apple", "banana", "orange"];
let reversedStrings = reverse(strings);
console.log(reversedStrings); // 輸出:["orange", "banana", "apple"]
透過使用泛型型別,函式reverse
可以適用於不同型別的陣列,提供了更高的靈活性和可重用性。
4. 泛型類:
泛型類允許我們建立可以適用於多種型別的類。類中的成員可以使用泛型型別進行宣告和使用。
舉個例子,考慮一個簡單的Box
類,用於儲存任意型別的值:
class Box<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
}
在這個例子中,我們定義了一個泛型類Box
,它具有一個私有成員value
和一個公共方法getValue
用於獲取值。
例如:
let box1 = new Box<number>(42);
console.log(box1.getValue()); // 輸出:42
let box2 = new Box<string>("Hello");
console.log(box2.getValue()); // 輸出:Hello
過使用泛型引數<T>
,可以在類的定義中引入型別變數來表示未知的型別。這樣一來,我們可以在類例項化時指定具體的型別,從而建立適用於不同型別資料的類的例項。
5. 泛型約束:
泛型約束允許我們限制泛型型別的範圍,使其滿足特定條件
5.1. 確保屬性存在
舉個例子,假設我們想編寫一個函式getLength
,用於獲取物件的長度。但是並不是所有的物件都有length
屬性,所以我們需要對泛型型別進行約束,確保它具有該屬性。
例如:
interface HasLength {
length: number;
}
function getLength<T extends HasLength>(obj: T): number {
return obj.length;
}
在這個例子中,我們使用泛型約束T extends HasLength
來限制泛型型別T
必須滿足HasLength
介面的要求,即具有length
屬性。
例如:
let str = "Hello";
console.log(getLength(str)); // 輸出:5
let arr = [1, 2, 3, 4, 5];
console.log(getLength(arr)); // 輸出:5
透過使用泛型約束,函式getLength
可以接受具有length
屬性的物件,並返回其長度。
5.2 檢查物件的 key
1、keyof typescript 中檢測型別的方法,以聯合型別的方式方返回型別的所有 key
2、搭配泛型約、<T,K extends keyof T >
refshttps://juejin.cn/post/6844904184894980104#heading-0
使用泛型,可以讓我們在編譯前發現錯誤。
6 泛型介面:
泛型介面允許我們定義可以適用於不同型別的介面。
舉個例子,考慮一個簡單的Transformer
介面,它定義了一個將輸入值轉換為輸出值的轉換器:
interface Transformer<T, U> {
transform(input: T): U;
}
在這個例子中,我們定義了一個泛型介面Transformer
,它有兩個型別引數T
和U
,用於定義輸入型別和輸出型別。
例如,我們可以實現一個字串到數字的轉換器:
class StringToNumberTransformer implements Transformer<string, number> {
transform(input: string): number {
return parseFloat(input);
}
}
透過定義實現了Transformer
介面的類,我們可以建立不同型別的轉換器。
例如:
let transformer = new StringToNumberTransformer();
let result = transformer.transform("3.14");
console.log(result); // 輸出:3.14
透過使用泛型介面,我們可以定義可重用、可靈活的介面,適用於不同型別的轉換操作。
介面搭配泛型,應用在 calss 類上
extend people 約束泛型類 在 people 介面範圍內
此時是 泛型變數佔位符,在例項化 class 類是傳遞型別
interface people {
name: string;
age: number;
}
class Popele<T extends people> {
data: T;
constructor(data: T) {
this.data = data;
}
hi() {
return `${this.data.name},,${this.data.age}`;
}
}
let zhagnsan = new Popele<people>({ name: "張三", age: 18 });
總結
泛型在 TypeScript 中提供了更靈活、可重用的程式碼編寫方式。它可以用於定義函式、類以及介面,讓我們能夠編寫適用於不同型別的程式碼。
讀者朋友好呀,我是王天~
嘗試做過很多事情,汽修專業肄業生,半路出道的野生程式設計師、前端講師、新手作者,最終還是喜歡寫程式碼、樂於用文字記錄熱衷分享~
如文章有錯誤或者不嚴謹的地方,期待給於指正,萬分感謝。
如果喜歡或者 有所啟發,歡迎 star,對作者也是一種鼓勵。
微信:「wangtian3111
」,加我進王天唯一的讀者群。
個人部落格:https://itwangtian.com