本篇將介紹在TypeScript如何使用泛型。html
在TypeScript裏,聲明泛型方法有如下兩種方式:數組
1 function generics_func1<T>(arg: T): T { 2 return arg; 3 } 4 // 或者 5 let generics_func2: <T>(arg: T) => T = function (arg) { 6 return arg; 7 }
調用方式也有兩種:this
1 generics_func1<string>('Hello world'); 2 // 或者 3 generics_func2('Hello world');
第二種調用方式能夠省略類型參數,由於編譯器會根據傳入參數來自動識別對應的類型。spa
在以前介紹的基本類型裏,有一個any類型,表示不肯定的類型。在具體使用時,能夠代替任意類型,好比以下方法定義和實現:code
1 function any_func(arg: any): any { 2 return arg; 3 } 4 5 any_func(1); 6 any_func('Hello world!'); 7 any_func(['1', '2']);
看似與泛型方法相似,可是仍是有區別的。好比以下例子:htm
1 // 方法一:帶有any參數的方法 2 function any_func(arg: any): any { 3 console.log(arg.length); 4 return arg; 5 } 6 7 // 方法二:Array泛型方法 8 function array_func<T>(arg: Array<T>): Array<T> { 9 console.log(arg.length); 10 return arg; 11 }
在方法一的方法體裏,打印了arg參數的length屬性。由於any能夠代替任意類型,因此該方法在傳入參數不是數組或者帶有length屬性對象時,會拋出異常。而方法二定義了參數類型是Array的泛型類型,確定會有length屬性,因此不會拋出異常。對象
從上面這個例子能夠看出,泛型類型相比較any類型來講,在某些狀況下會帶有類型自己的一些信息,而any類型則沒有。blog
如下是一個泛型類的定義和調用繼承
1 class Generics_Demo<T>{ 2 value: T; 3 show(): T { 4 return this.value; 5 } 6 } 7 8 let gene_demo1 = new Generics_Demo<number>(); 9 gene_demo1.value = 1; 10 console.log(gene_demo1.show()); // 調用方法 11 12 gene_demo1.show = function () { return gene_demo1.value + 1; } // 賦值新方法,返回值類型必須是number 13 console.log(gene_demo1.show());
經過指定明確類型的泛型類的實例,對屬性賦值時,必須知足實際類型的約束。接口
如下幾個例子都是利用泛型類型定義變量或者方法參數的類型的示例
1. 泛型接口
1 interface Generics_interface { 2 <T>(arg: T): T; 3 } 4 5 function func_demo<T>(arg: T): T { 6 return arg; 7 } 8 9 let func1: Generics_interface = func_demo;
上面的例子裏,接口只有一個泛型方法成員。則用此接口類型定義的變量就是一個與成員類型一致的泛型方法。
將上面例子的泛型接口稍微改一下
1 interface Generics_interface<T> { 2 (arg: T): T; 3 } 4 5 function func_demo<T>(arg: T): T { 6 return arg; 7 } 8 9 let func1: Generics_interface<number> = func_demo; 10 func1(123); // 正確類型的實際參數 11 func1('123'); // 錯誤類型的實際參數
經過在接口上聲明泛型,聲明變量時明確指定泛型的具體類型,則賦值的方法將自動帶上具體的類型約束。
2. 泛型類型繼承
1 interface LengthInterface { 2 length: number; 3 } 4 5 function func_demo<T extends LengthInterface>(arg: T): T { 6 console.log(arg.length); 7 return arg; 8 } 9 10 func_demo({ a: 1, length: 2 }); // 含有length屬性的對象 11 func_demo([1, 2]); // 數組類型
上面的例子裏,泛型類型繼承自一個擁有length屬性成員的接口,泛型類型將自動加上length屬性的約束。調用時只有符合條件的對象才能正確賦值。
1 function copy<T extends U, U>(source: U, target: T): T { 2 for (let prop in source) { 3 target[prop] = source[prop]; 4 } 5 6 return target; 7 } 8 9 copy({ a: 1, b: 2 }, { a: 2, b: 3, c: 4 }); // 正確的實際參數 10 copy({ a: 1, b: 2 }, { q: 2, c: 4 }); // 錯誤的實際參數
在上面的例子裏,一個泛型類型繼承自另一個泛型類型。在方法調用時,就必須確保繼承類型對應的參數對象屬性徹底包含被繼承類型對應的參數對象。