TS学习笔记4:泛型

116 阅读2分钟

点击此处访问本文所属专栏

泛型是利用变量来表达类型的方式,在定义函数、接口或者类的时候,先用这个类型变量表示类型,在实际使用的时候才将数据类型传给类型变量,以达到一段程序可以适应多种类型的目的。泛型一般用大写字母表示,最常见的是' T '。

1.在函数中使用泛型

下面函数中的<T>就是一个泛型变量。在函数最前面传入后,函数内部就可以使用这个泛型。例子中我们给T传入了number类型,则getArray的函数在执行时只能传入number类型的参数。

const getArray = <T>(value: T, times: number = 5): T[] => {
    return new Array(times).fill(value)
}
console.log(getArray<number>(1))  // 

2.使用两个泛型变量

// 两个泛型变量 T 和 U
 const getArray =  <T, U>(param1: T, param2: U, times: number): [T, U][] => {
     return new Array(times).fill([param1, param2])
 }

TS编辑器会根据传入的值自动补充T和U传入的值,下面的例子中,T和U分别被隐式赋予了number和string两个类型值。

const arr = (getArray(1,'a',3))
console.log(arr)  // [[1,'a'],[1,'a'],[1,'a']]

后续操作中,如果对非number型的变量使用了number型的静态方法,则编辑器会报错

arr[0][1].toFixed()  // error

3. 使用泛型定义函数类型

 let getArray: <T>(arg: T, times: number) => T[]
 getArray = (value: any, times: number ) => {
     return new Array(times).fill(value)
 }

4. 在类型别名中使用泛型

type GetArray = <T>(arg: T, times:number) => T[]
let getArray: GetArray = (arg: any, times:number) => {
    return new Array(times).fill(arg)
}

5.在接口中使用泛型

在接口内部定义:

 interface GetArray {
     <T>(arg: T, times:number): T[]
 }

在接口外层定义,好处是每个属性都可以使用:

 interface GetArray<T> {
    (arg: T, times:number): T[],
     array: T[]
 }
  1. 泛型约束 泛型约束是对泛型的一种限制,如下面的例子,我们先定义一个接口ValueWithLength,然后让泛型T extends ValueWithLength,则根据接口的定义,T现在被限制为传入的类型必须有length属性:
interface ValueWithLength {
     length: number
 }
const getArray = <T extends ValueWithLength>(arg: T, times): T[] => {
     return new Array(times).fill(arg)
}

下面的例子,通过两个泛型的限制,实现了获取对象属性值时的检测功能:

const getProps = <T, K extends keyof T>(object: T, propName: K) => {
    return object[propName]
}

const objs = {
    a: 'a',
    b: 'b'
}

getProps(objs, 'a')  // 'a'
getProps(objs, 'c')  // error,对象objs上不存在c这个属性