TypeScript躬行記(4)——泛型


  泛型是程序設計語言中的一種風格或范式,相當於類型模板,允許在聲明類、接口或函數等成員時忽略類型,而在未來使用時再指定類型,其主要目的是為它們提供有意義的約束,提升代碼的可重用性。

一、泛型參數

  當一個函數需要能處理多種類型的參數和返回值,並且還得約束它們之間的關系(例如類型要相同)時,就可以采用泛型的語法,如下所示。

function send<T>(data: T): T {
  return data;
}

  函數名稱后面跟了<T>,其中把T稱為泛型參數或泛型變量,表示某種數據類型。注意,T只是個占位符,可以命名的更含語義,例如TKey、TValue等。在使用時,既可以指定類型,也可以利用類型推論自動確定類型,如下所示。

send<number>(10);        //指定類型
send(10);              //類型推論

  當需要處理T類型的數組時,可以像下面這么寫。

function send<T>(data: T[]): T[] {
  return data;
}
send<number>([1, 2, 3]);

  當指定一個泛型函數的類型時,需要包含泛型參數,如下所示,其中泛型參數和函數參數的名稱都可與定義時的不同。

let func: <U>(data: U) => U = send;

  泛型參數還支持傳遞多個,只需在聲明時增加類型占位符即可。在下面的示例中,將T和U合並成了一個元組類型,還有許多其它用法,將在后面講解。

function send<T, U>(data: [T, U]): [T, U] {
  return data;
}
send<number, string>([1, "a"]);

二、泛型接口

  在接口中,可利用泛型來約束函數的結構,如下所示,接口中聲明的調用簽名包含泛型參數。

interface Func {
  <T>(str: T): T;
}
function send<T>(str: T): T {
  return str;
}
let fn: Func = send;

  泛型參數還可以作為接口的一個參數存在,即把用尖括號包裹的泛型參數移到接口名稱之后,如下所示。

interface Func<T> {
  (str: T): T;
}
function send<T>(str: T): T {
  return str;
}
let fn: Func<string> = send;

  當把Func接口作為類型使用時,需要向其傳入一個類型,例如上面賦值語句中的string。

三、泛型類

  泛型類與泛型接口類似,也是在名稱后添加泛型參數,如下所示,其中send屬性中的“=>”符號不表示箭頭函數,而是用來定義方法的返回值類型。

class Person<T> {
  name: T;
  send: (data: T) => T;
}

  在實例化泛型類時,需要為其指定一種類型,如下所示。

let person = new Person<string>();
person.send = function(data) {
  return data;
}

  注意,類的靜態部分不能使用泛型參數。

四、泛型約束

  在使用泛型時,由於事先不清楚參數的數據類型,因此不能隨意調用它的屬性或方法,甚至無法對其使用運算符。在下面的示例中,訪問了data的length屬性,但由於編譯器無法確定它的類型,因此就會報錯。

function send<T>(data: T): T {
  console.log(data.length);
  return data;
}

  TypeScript允許為泛型參數添加約束條件,從而就能調用相應的屬性或方法了,如下所示,通過extends關鍵字約束T必須是string的子類型。

function send<T extends string>(data: T): T {
  console.log(data.length);
  return data;
}

  在添加了這個約束之后,send()函數就無法接收數字類型的參數了,如下所示。

send("10");        //正確
send(10);          //錯誤

1)創建類的實例

  在使用泛型創建類的工廠函數時,需要聲明T類型擁有構造函數,如下所示。

class Programmer { }
function create<T>(ctor: {new(): T}): T {
  return new ctor();
}
create(Programmer);

  用“{new(): T}”替代原先的類型占位符,表示可以被new運算符實例化,並且得到的是T類型,另一種相同作用的寫法如下所示。

function create<T>(ctor: new()=>T): T {
  return new ctor();
}

2)多個泛型參數

  在TypeScript中,多個泛型參數之間也可以相互約束,如下所示,創建了基類Person和派生類Programmer,並將create()函數中的T約束為U的子類型。

class Person { }
class Programmer extends Person { }
function create<T extends U, U>(target: T, source: U): T {
  return target;
}

  當傳遞給create()函數的參數不符合約束條件時,就會在編譯階段報錯,如下所示。

create(Programmer, Person);        //正確
create(Programmer, 10);            //錯誤

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM