TypeScript 泛型
TypeScript 泛型
需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 类型变量,它是一种特殊的变量,只用于表示类型而不是值。
function identity<T>(arg: T): T {
return arg;
}
我们给identity添加了类型变量T。 T帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 之后我们再次使用了 T当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。 这允许我们跟踪函数里使用的类型的信息。
我们把这个版本的identity函数叫做泛型,因为它可以适用于多个类型。 不同于使用 any,它不会丢失信息,像第一个例子那像保持准确性,传入数值类型并返回数值类型。
定义了泛型函数后,可以用两种方法使用。 第一种是,传入所有的参数,包含类型参数:
let output = identity<string>("myString"); // type of output will be 'string'
这里我们明确的指定了T是string类型,并做为一个参数传给函数,使用了<>括起来而不是()。
第二种方法更普遍。利用了类型推论 -- 即编译器会根据传入的参数自动地帮助我们确定T的类型:
let output = identity("myString"); // type of output will be 'string'
使用泛型变量
使用泛型创建像identity这样的泛型函数时,编译器要求你在函数体必须正确的使用这个通用的类型。 换句话说,你必须把这些参数当做是任意或所有类型。
打印 arg长度
错误用法
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
正确用法
只要传入的类型有这个属性,我们就允许,就是说至少包含这一属性。
function loggingIdentity<T>(arg: T[]): T[] {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
// 或者
function loggingIdentity<T>(arg: Array<T>): Array<T> {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
泛型接口
identities() 所做的是将类型 T 和 U 传递到函数和 Identities 接口中,使我们能够定义与参数类型相关的返回类型。
interface Identities<V, W> {
id1: V,
id2: W
}
function identities<T, U> (arg1: T, arg2: U): Identities<T, U> {
console.log(arg1 + ": " + typeof (arg1));
console.log(arg2 + ": " + typeof (arg2));
let identities: Identities<T, U> = {
id1: arg1,
id2: arg2
};
return identities;
}
泛型类
泛型类看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
//可以使用数字类型
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
//可以使用字符串类型
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };
console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));
与接口一样,直接把泛型类型放在类后面,可以帮助我们确认类的所有属性都在使用相同的类型。
类有两部分:静态部分和实例部分。 泛型类指的是实例部分
的类型,所以类的静态属性不能使用这个泛型类型。
泛型约束
想访问arg的length属性,但是编译器并不能证明每种类型都有length属性,所以就报错了
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
想要限制函数去处理任意带有.length属性的所有类型。 只要传入的类型有这个属性,我们就允许,就是说至少包含这一属性,需要列出对于T的约束要求。
定义一个接口来描述约束条件。 创建一个包含 .length属性的接口,使用这个接口和extends关键字还实现约束:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在我们知道它具有.length属性,因此不再有错误
return arg;
}
loggingIdentity(3); // Error, number doesn't have a .length property
loggingIdentity({length: 10, value: 3}); //正确