一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第24天,点击查看活动详情。
在TypeScript中最难理解的就是泛型,学会熟练的使用泛型我们的TypeSCript的能力就会有很大提升,今天来总结一下泛型的基本使用和一些应用场景
什么是泛型
泛型程序设计(generic programming)是程序设计语言的一种风格或范式
泛型允许我们在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型,在typescript中定义函数,接口或者类的时候,不预先定义好具体的类型,而在使用的时候在指定类型的一种特性。
简单来说泛型就是参数化类型
假设我们需要一个函数,它可接受一个 number 参数并返回一个number 类型的返回值
function fn (num: number): number {}
假设我们又需要一个函数,它可接受一个 string 参数并返回一个string类型的返回值
function fn (num: string): string {}
上述这两个需求写出的代码,存在一个最明显的问题在于,代码重复度比较高
虽然我们可以使用 any类型去替代,但使用any类型TypeScript也就失去了意义,我们的目的是接收什么类型的参数返回什么类型的参数,需要运行时传入参数我们才能确定类型然后返回这个类型
这种情况就需要使用泛型
function fn<T> (num: T): T {}
fn(1)
这里调用函数时传递的实参是什么类型,fn的形参就是什么类型,返回值同样也是这个类型,实现了代码的复用
泛型的使用方式
泛型通过<>的形式进行表述,主要有这三种使用形式:
- 泛型函数
- 泛型接口
- 泛型类 泛型函数
刚我们上面例子里的函数就是一个简单的泛型函数,定义泛型的时候,可以一次定义多个类型参数,比如我们可以同时定义泛型 T 和 泛型 U
function fn<T, U> (valuse: [T, U]): [T, U] {
return [valuse[0], valuse[1]]
}
fn([8, 'a'])
这样就可以传入两个泛型参数,函数定义类型就是定义参数的类型和返回值的类型
泛型接口
interface Result<T> {
fn(num:T): T // 普通函数写法,参数是T类型返回值是T类型
fn1: (num:T) => T // 箭头函数写法,参数是T类型返回值是T类型
name: string
}
const obj:Result<number> // 给接口传递类型
泛型类
使用泛型声明类的时候,既可以作用于类本身,也可以作用于类的成员函数
class Stack<T> {
private arr: T[] = []
public push(item: T) {
this.arr.push(item)
}
public pop() {
this.arr.pop()
}
}
使用方式
const stack = new Stacn<number>()
如果要求只能传递strign 和number类型,这时候可以配后继承的方式使用,实现约束类型
class Stack<T extends Constraint>{
private arr: T[] = []
}
除了上述的形式,泛型还有更高级的使用
比如需要一个函数,这个函数接受两个参数,一个参数为对象,另一个参数为对象上的属性,我们通过这两个参数返回这个属性的值
interface Obj {
name:'小王',
age:23
}
function fn<T extends obj,U extends keyof T>(obj:T,key:U){
return obj[key]
}
这里T继承了接口接口obj上的属性,然后U又通过keyof继承了T上的属性名,所以U这个类型里面就是字面量类型name|age
多类型约束使用
比如需要实现两个接口的类型约束
interface First {
fn():number
}
interface Second {
fn1:()=>string
}
//同时继承两个接口
interface Third extends First,Second {}
通过泛型约束达到多类型约束的目的