TypeScript中的泛型使用详解

一、泛型的概述

"泛"就是广泛的意思,"型"就是数据类型。顾名思义,泛型就是适用于多种数据类型的一种类型。

它能够帮助我们构建出复用性更强的代码。

假如有如下函数:

function sum(num: number): number {
    
    
  return num
}

此时函数的参数和返回值都必须是number类型的。

但是其它类型的数据,比如stringboolean或者自定义的Teacher等类型就没有办法使用这个函数。

虽然any可以解决这个问题,但是函数参数和返回值定义为any的时候,具体的类型信息就已经丢失了。

比如传入的是一个number,那么我们希望返回的并不是any类型,而是number类型。

所以,我们需要在函数中可以捕获到参数的类型是number,并且同时使用它来作为返回值的类型。

因此需要在这里使用一种特性的变量 - 类型变量(type variable),它作用于类型,而不是值!

二、泛型的基本使用

2.1 泛型函数示例

在定义一个函数时,不决定这些参数的类型,而是让调用者以参数的形式告知函数参数应该是什么类型。

function sum<T>(num: T): T {
    
    
  return num
}

我们可以把Type看做额外的一个参数,把类型参数化。

扫描二维码关注公众号,回复: 15670239 查看本文章

它可以做到, 在定义这个函数时, 不决定这些参数的类型, 而是让调用者以参数的形式告知, 这里的函数参数应该是什么类型。

2.2 传入泛型的方式

函数定义时,<>的位置就是之后泛型的传入位置,比如上面函数的<T>

传入泛型时,只要把具体的泛型传递给<T>即可。

这样函数定义时的,函数参数,和函数返回值的T类型,都会变成传入的具体参数类型。

1)通过 <类型> 的方式将泛型传递给函数

sum<number>(100) 						// 声明sum函数的泛型为number类型,并传递number类型的参数
sum<{
      
      name: string}>({
    
     name: "zs" }) 	// 声明sum函数的泛型为{name: string}类型
sum<number[]>([15, 25]) 				// 声明sum函数的泛型为number类型的数组

2)通过类型推导,自动推到出我们传入变量的类型

在这里会推导出它们是 字面量类型的,因为字面量类型对于我们的函数也是适用的

sum(100)
sum("test")

三、常用的泛型名称

开发中可能会看到一些常用的名称,不同的名称会有不同语义化意义。

  • TType的缩写,类型

  • K、Vkeyvalue的缩写,键值对

  • EElement的缩写,元素

  • OObject的缩写,对象

四、传入多个泛型

function fun<T, E>(arg1: T, arg2: E) {
    
    
  console.log(arg1, arg2)
}

fun<number, string>(100, "test")

当一个函数有多个泛型时,可以用不同的泛型名称来标识。

上面的fun函数的参数一的类型由泛型T决定,而参数二由泛型E决定。

五、泛型接口

在定义接口的时候也可以使用泛型来对接口内的成员进行类型约束。

2.1 泛型接口的基本使用

interface IInfo<T1, T2> {
    
    
  name: T1
  age: T2
}

const info: IInfo<string, number> = {
    
    
  name: "zs",
  age: 25
}

2.2 泛型接口中的基本使用

泛型接口是没有类型推导的, 但是可以有泛型默认值。

// 泛型接口定义默认类型
interface IPerson<T1 = string, T2 = number> {
    
    
  name: T1
  age: T2
}

const p: IPerson = {
    
    
  name: "chenyq",
  age: 123
}

六、泛型类的使用

class Point<T> {
    
    
  x: T
  y: T
  z: T

  constructor(x: T, y: T, z: T) {
    
    
    this.x = x
    this.y = y
    this.z = y
  }
}

// 泛型类自动推导类型
const point1 = new Point("1.33.2", "2.22.3", "4.22.1")
// 泛型类明确泛型类型
const point2 = new Point<string>("1.33.2", "2.22.3", "4.22.1")
const point3: Point<string> = new Point("1.33.2", "2.22.3", "4.22.1")


数组泛型的写法:

// 定义字符串数组
const arr1: string[] = ["a", "b", "c"]			
const arr2: Array<string> = ["a", "b", "c"]

七、泛型约束

有时候希望传入的类型具有某些共性,但是这些共性可能不是在同一种类型中。

比如stringarray都是有length的,或者某些对象也是会有length属性的。

那么只要是拥有length的属性都可以作为我们的参数类型。

interface ILength {
    
    
  length: number
}

// 泛型继承接口, 这样传入的泛型类型就必须和ILength接口一样具有length属性才可以
function getLength<T extends ILength>(arg: T) {
    
    
  console.log(arg.length)
}

// getLength(123) 			// 123没有length无法传入
getLength("abcdefg") 		// 7
getLength([10, 20, 30, 40]) // 4
getLength({
    
     length: 20 })	// 10

T extends表示传入的类型必须是extends后面的类型或者子类型。

猜你喜欢

转载自blog.csdn.net/qq_44749491/article/details/127545292