TypeScript學習筆記(六):泛型


認識泛型

TypeScript也實現了類型於C#和Java的泛型以實現類型的參數化,我們先看一個需求:

1 function identity(arg: any): any {
2     return arg;
3 }

我們希望方法identity可以傳入任意類型,並且返回傳入的類型,這樣寫可以達到效果但是不能確定返回的類型,使用泛型的寫法如下:

1 function identity<T>(arg: T): T {
2     return arg;
3 }
4 
5 var output = identity<string>("myString");  // type of output will be 'string'
6 var output = identity("myString");  // type of output will be 'string'

我們可以指定類型,也可以讓編譯器自動來識別類型。

泛型數組

我們也可以通過泛型來指定一個數組,寫法如下:

1 function loggingIdentity<T>(arg: T[]): T[] {
2     console.log(arg.length);  // Array has a .length, so no more error
3     return arg;
4 }
5 
6 function loggingIdentity<T>(arg: Array<T>): Array<T> {
7     console.log(arg.length);  // Array has a .length, so no more error
8     return arg;
9 }

泛型類型

我們可以指定一個帶有泛型的函數:

1 function identity<T>(arg: T): T {
2     return arg;
3 }
4 
5 var myIdentity: <U>(arg: U)=>U = identity;

還有另一種寫法:

1 function identity<T>(arg: T): T {
2     return arg;
3 }
4 
5 var myIdentity: {<T>(arg: T): T} = identity;

使用函數接口的寫法如下:

1 interface GenericIdentityFn {
2     <T>(arg: T): T;
3 }
4 
5 function identity<T>(arg: T): T {
6     return arg;
7 }
8 
9 var myIdentity: GenericIdentityFn = identity;

同時泛型還可以作為類型的參數而不是方法的參數,寫法如下:

1 interface GenericIdentityFn<T> {
2     (arg: T): T;
3 }
4 
5 function identity<T>(arg: T): T {
6     return arg;
7 }
8 
9 var myIdentity: GenericIdentityFn<number> = identity;

泛型類

泛型除了可以用在接口上以外,當然還可以用在類上:

 1 class GenericNumber<T> {
 2     zeroValue: T;
 3     add: (x: T, y: T) => T;
 4 }
 5 
 6 var myGenericNumber = new GenericNumber<number>();
 7 myGenericNumber.zeroValue = 0;
 8 myGenericNumber.add = function(x, y) { return x + y; };
 9 
10 var stringNumeric = new GenericNumber<string>();
11 stringNumeric.zeroValue = "";
12 stringNumeric.add = function(x, y) { return x + y; };
13 alert(stringNumeric.add(stringNumeric.zeroValue, "test"));

使用方法和C#與Java一致。

泛型約束

之前的泛型可以是任意的類型,我們還可以約束泛型的類型,我們先看一個會報錯的例子:

1 function loggingIdentity<T>(arg: T): T {
2     console.log(arg.length);  // Error: T doesn't have .length
3     return arg;
4 }

報錯原因是,類型T沒有length屬性,我們可以為類型T指定一個類型,如下:

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

寫法是通過extends來指定類型T的類型必須是實現了Lengthwise接口的類型。

調用如下:

1 loggingIdentity(3);  // Error, number doesn't have a .length property
2 loggingIdentity({length: 10, value: 3});  

泛型約束泛型

某些情況下,我們可能會有如下的需求:

1 function find<T, U extends Findable<T>>(n: T, s: U) {   // errors because type parameter used in constraint
2   // ...
3 } 
4 find (giraffe, myAnimals);

這種寫法會報錯,可以使用下面正確的寫法來達到效果:

1 function find<T>(n: T, s: Findable<T>) {   
2   // ...
3 } 
4 find(giraffe, myAnimals);

在泛型中使用類類型

有時我們希望可以指定泛型的構造函數和屬性,寫法如下:

1 function create<T>(c: {new(): T; }): T { 
2     return new c();
3 }

再看另外一個例子:

 1 class BeeKeeper {
 2     hasMask: boolean;
 3 }
 4 
 5 class ZooKeeper {
 6     nametag: string; 
 7 }
 8 
 9 class Animal {
10     numLegs: number;
11 }
12 
13 class Bee extends Animal {
14     keeper: BeeKeeper;
15 }
16 
17 class Lion extends Animal {
18     keeper: ZooKeeper;
19 }
20 
21 function findKeeper<A extends Animal, K> (a: {new(): A; 
22     prototype: {keeper: K}}): K {
23 
24     return a.prototype.keeper;
25 }
26 
27 findKeeper(Lion).nametag;  // typechecks!

 


免責聲明!

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



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