目录

一个例子!!

  泛型变量

一个问题,报错了!

  泛型约束

  使用泛型函数

  泛型接口

  泛型类

一个例子!!

创建一个identity函数:这个函数会返回任何传入它的值。

不用泛型:

function identity(arg: number): number {
    return arg;
}

或者,使用any类型来定义函数:

function identity(arg: any): any {
    return arg;
}

那么,使用any类型会导致这个函数可以接收任何类型的arg参数。

泛型变量

对于上面的例子,我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 类型变量一种特殊的变量,只用于表示类型而不是值

用了泛型:

function identity<T>(arg: T): T {
    return arg;
}

  帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 之后我们再次使用了  T 当做返回值类型。 

一个问题,报错了!

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

注:这些类型变量代表的是任意类型,所以使用这个函数的人可能传入的是个数字,而数字是没有 .length属性的。

我们可以这样:

function loggingIdentity<T>(arg: T[]): T[] {
    console.log(arg.length);  // Array has a .length, so no more error
    return arg;
}

泛型约束

还可以怎么解决上面那个问题呢,那么,我们定义一个接口来描述约束条件。 创建一个包含 .length属性的接口,使用这个接口和extends关键字来实现约束

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // Now we know it has a .length property, so no more error
    return arg;
}

继而,现在这个泛型函数被定义了约束,因此它不再是适用于任意类型

loggingIdentity(3);  // Error, number doesn't have a .length property

我们需要传入符合约束类型的值,必须包含必须的属性:

loggingIdentity({length: 10, value: 3});

使用泛型函数

第一种:传入所有的参数,包含类型参数

let output = identity<string>("myString");  // type of output will be 'string'

这里我们明确的指定了 T string类型,并做为一个参数传给函数,使用了<>括起来。

第二种:利用了类型推论 -- 即编译器会根据传入的参数自动地帮助我们确定T的类型

let output = identity("myString");  // type of output will be 'string'

泛型函数的类型与非泛型函数的类型没什么不同,只是有一个类型参数在最前面

function identity<T>(arg: T): T {
    return arg;
}

//也可以使用不同的泛型参数名 T-->U
let myIdentity: <T>(arg: T) => T = identity;

泛型接口

interface GenericIdentityFn {
    <T>(arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn = identity;

// 我们可能想把泛型参数当作整个接口的一个参数。 这样我们就能清楚的知道使用的具体是哪个泛型类型
let myIdentity: GenericIdentityFn<number> = identity;

泛型类

看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。

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; };

与接口一样,直接把泛型类型放在类后面,可以帮助我们确认类的所有属性都在使用相同的类型。