前端深入理解Typescript泛型概念

首先介绍一下泛性的概念

泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。

泛型是指在定义函数,接口或者类的时候,不预先定义好具体的类型,而在使用的时候在指定类型的一种特性。

先举一个简单的例子

假设我们定义一个函数,它可以接收一个number类型做为参数,并且返回一个number类型。

function genericDemo(data: number): number { return data; }

按照以上的写法是没有问题的,但是如果我们要接受一个string并返回一个string呢?如果逻辑一样还要在写一遍吗?就像下面这样。

function genericDemo(data: string): string { return data; }

这显然代码是很冗余的,我们还有不使用any的写法吗?答案是显然易见的,可以使用范型的写法,就像下面这样。

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

我们在函数名称genericDemo后面声明了范型变量<T>,他用于捕获调用该函数时传入的参数类型(例如:number),之后我们就可以使用这个类型。 之后我们再次使用了T当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。这允许我们跟踪函数里使用的类型的信息。

多个类型参数

我们在定义范型的时候,也可以一次定义多个类型参数,像下面这样。

function swap<T, U>(tuple: [T, U]):[U, T] { return [tuple[1], tuple[0]]; }

泛型接口

我们先定义一个范型接口Identities,然后定义一个函数identities()来使用这个范型接口

interface Identities<T, U> { id1: T; id2: U; }

我在这里使用T和U作为我们的类型变量来演示任何字母(或有效的字母数字名称的组合)都是有效的类型—除了常规用途之外,您对它们的调用没有任何意义。

我们现在可以将这个接口应用为identity()的返回类型,修改我们的返回类型以符合它。我们还可以console.log这些参数和它们的类型,以便进一步说明:

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

我们现在对identity()所做的是将类型T和U传递到函数和identity接口中,从而允许我们定义与参数类型相关的返回类型。

范型变量

使用泛型创建像identity这样的泛型函数时,编译器要求你在函数体必须正确的使用这个通用的类型。 换句话说,你必须把这些参数当做是任意或所有类型。

我们先看下之前例子

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

如果我们想同时打印出data的长度。 我们很可能会这样做

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

如果这么做,编译器会报错说我们使用了data的.length属性,但是没有地方指明data具有这个属性。 记住,这些类型变量代表的是任意类型,所以使用这个函数的人可能传入的是个数字,而数字是没有.length属性的。

现在假设我们想操作T类型的数组而不直接是T。由于我们操作的是数组,所以.length属性是应该存在的。 我们可以像创建其它数组一样创建这个数组:

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

范型类

我们还可以在类属性和方法的意义上使类泛型。泛型类确保在整个类中一致地使用指定的数据类型。例如下面这种在React Typescript项目中的写法。

interface Props { className?: string; ... } interface State { submitted?: bool; ... } class MyComponent extends React.Component<Props, State> { ... }

我们在这里使用与React组件一起使用的泛型,以确保组件的props和state是类型安全的。

泛型约束

我们先看一个常见的需求,我们要设计一个函数,这个函数接受两个参数,一个参数为对象,另一个参数为对象上的属性,我们通过这两个参数返回这个属性的值,比如:

function getValue(obj: object, key: string){ return obj[key] // error }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/aea416b7999757c7a02fd99f59119e02.html