TypeScript - 泛型

本文介绍了TypeScript中的泛型,从值和类型的概念出发,解释了泛型的必要性和作用。通过实例展示了如何使用泛型进行类型编程,包括泛型函数、泛型约束等,并探讨了何时适合使用泛型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        最近上手TS,泛型是我一直迷糊的点,官网泛型的部分反反复复看了好几遍,讲解泛型的文章也看了不少,好像是懂了,又好像不懂。
        如果问我泛型是什么,嗯,支持多类型数据?传入类型影响输出类型?理解成更严格的any?带<>?如果你的回答和我一样,恭喜你,你已经达到了你以为你懂,实战就蒙的境界~(不信,去找个开源TS项目的源码看看。)
        今天终于搞明白泛型了,写一个笔记,文章有点长,如果你也是TS小白,强烈建议看一下,因为我也是小白,我懂你~如果你是大佬,点关闭~哈哈哈哈哈

一、值和类型 *

        泛型是一种抽象类型,string,number,boolean等是一种具体类型,具体类型我们多是对值进行编程,泛型是对类型进行编程。
        这句话听起来抽象,但是最终我明白了泛型,也是因为这句话。

1、对值编程
  • TS中我们常用的就是对值限定类型。从集合论的角度上来说, 值的集合就是类型。
  • 下面的例子,可以看出是对具体的值 ‘lianlian’ 进行编程,字符串 ‘lianlian’ 就是 string 类型的一个具体的值 。所以,这就是我们常用的对值限定类型,对值进行的编程。
function sayName(name: string) {
	console.log(`my name is ${name}`)
}
sayName('lianlian')
二、泛型

        上面说了很多,我们了解了类型和值的区别。也了解了我们平时使用的简单类型,本质上都是对值进行编程,只是在编程之前,对将值限定了类型~

1、为什么需要泛型

        想实现一个identity函数,这个函数会返回任何传入它的值(肯定传入和返回的类型也是相同)。(官网上你一定看过这个函数例子~)。
        可以使用any这样写,但是这样写会丢失一些信息:传入的类型和返回的类型要求是相同的。如果我们传入一个’lianlian’,只知道任何类型的值都有可能被返回。

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

        可以这样写,这样就可以保证传入的类型和返回的类型是一致的,但是写法是不是太笨了?JS提供了多少种类型,我们就要复制多少遍。

function identityNumber(arg: number): number { return arg }
function identityString(arg: string): string { return arg }
......

        所以为了解决上面的问题,我们就需要泛型。此时 T 是一个抽象类型,只有在调用方法的时候,才能确定类型。所以当我们传入参数‘lianlian’时,T表示了string类型。

  • <T>:函数声明一个表示类型的变量(所以此处T,U等其他字母都可以)
  • (arg: T):函数传入的参数是 T 类型.
  • (): T:函数的返回值也是 T 类型.
function identity<T>(arg: T): T { return arg }
identity('lianlian')
2、泛型是对类型的编程

        这句话的意思呢?看下面的栗子🌰~
        开始我定义了一个Person 类,有三个属性,都是必填选项,用于用户注册。

enum Sex {
    male,
    female,
    unknow
}

type Persion =  {
    name: string,
    sex: Sex,
    age: number
}

        突然新增一个组件用于开展活动,也要用到Person类,要求是原有的属性变为可选。怎么办?

  1. 重新写一个AvtivityPerson 类
  2. 利用泛型,其中我利用了一个TS内置的类型别名(工具类) Partial<T>,Partial作用是让 T 中的所有属性都是可选的。
/**
 * TS 源码
 * Make all properties in T optional 
 */
type Partial<T> = {
    [P in keyof T]?: T[P];
};
// 重写类
type AvtivityPerson = {
    name?: string,
    sex?: Sex,
    age?: number,
}
// 利用泛型
type AvtivityPerson = Partial<Persion> 

在这里插入图片描述
        看图,泛型是不是和普通函数很相似(定义和使用)?普通函数操作的是值,而泛型是将类型看成值进行操作。可以看出泛型函数是接收一个类型作为参数,最后返回一个类型。
在这里插入图片描述
在这里插入图片描述

三、泛型的种类

上面介绍泛型的使用时,示例中泛型的用法时泛型函数,泛型还包括泛型类泛型接口。用法和泛型函数

// 泛型接口
interface CheckBoxGripProps<T> {
    value: T[]
    disabled?: boolean
}

// 泛型类
export default class CheckboxGrid extends tsx.Component<CheckBoxGripProps<T>> 
四、泛型约束

        我们可以对函数的参数进行约束,就像对 sayName 函数的形参进行类型约束,使得函数只能接收 string 类型的参数一样,泛型也可以进行约束
        举例,函数中想打印参数的size,但是参数类型中没有size属性,所以会报错,解决办法就是限定传给trace函数的参数类型中必须有size属性!使用关键字extends就可以实现。

// 报错的
function trace<T>(arg: T): T { 
	console.log(arg.size) // 类型“T”上不存在属性“size”
	return arg
}

// 泛型约束
interface Size {
    size: number
}

function trace<T extends Size>(arg: T): T {
	console.log(arg.size) 
	return arg
}
五、什么时候使用泛型

看完上面的例子,当你的接口、函数、类有如下使用情况时,可以使用泛型:

  1. 参数是多类型时,比如 identity 函数的泛型声明。
  2. 多处使用时,比如 Partial 泛型。

最后:
感谢下面的文档,都是我学泛型的时候看的~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值