TypeScript中泛型函数

一.概览

此前,对泛型有了整体的概览,详见TypeScript中的泛型,后面的系列会详细地介绍TypeScript的泛型。此篇文章主要介绍泛型函数

二. 泛型函数

泛型是类型不明确的数据类型,在定义时,接收泛指的数据类型(不知道具体是什么类型),在使用时,指定明确的数据类型的一种给定类型的方式。

泛型定义的位置:

  1. 函数声明: 写在函数名后面;
  2. 函数表达式: 写在表达式最前面

泛型调用的位置
在函数名后面跟泛型
传入具体的数据类型![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/70597a0664884784b3270b4e7e35e70a.png

1.泛型函数的引入具体是为了解决什么问题呢?

举个例子

function getSplitValue(value: string[],type: string):string {
    return value.join(type)
}

function getSplitValue2(value: number[],type: string):string {
    return value.join(type)
}

getSplitValue(['1','2','3'],',')
getSplitValue2([1,2,3],',')

问题:两个函数内部的逻辑完全一样,但由于传递参数的类型不同,导致了不得不定义两个函数去处理两个不同类型的数组

解决方案:用一种类型兼容两种不同类型的数组

第一种方法,可以使用any

value: any[]

缺点:如果想在使用函数时明确数组元素类型时,any就不适合了,用any会使约束变小

第二种方法: 使用泛型

function getSplitValue3<E>(value: E[],type: string):string {
    return value.join(type)
}

const aa = getSplitValue3<string>(['a','b','c'],',')
const bb = getSplitValue3<number>([1,2,3],',')
console.log(aa) // 'a,b,c'
console.log(bb) // '1,2,3'

最小范围为any的场景,基本上都可以使用泛型

2. 泛型函数复用

type TypePlus<T> = (a: T, b: T) => T
type TypeNumberPlus<T,U> = (a: T, b: U) => string

const plusNumber: TypePlus<number> = (a,b) => {
    return a + b
}

const plusString: TypePlus<string> = (a,b) => {
    return a + b
}
const numberPlus: TypeNumberPlus<number,string> = (a,b) => {
    return a + b
}
console.log(plusNumber(1,2))
console.log(plusString('1','2'))
console.log(numberPlus(9,'aa'))

可以将公共部分封装起来,有点像js中的柯里化。

3. 泛型约束

举个例子

function plusNumber(a: number,b:number):number {
    return a + b
}

指定特定类型,正常编译

function plusNumber<T>(a: T,b:T):number {
    return a + b
}

指定泛型,编译报错
编译报错:运算符“+”不能应用于类型“T”和“T”

报错原因:它们可以是任何类型(由泛型 T 表示),然后返回这两个参数的和。
但是,有一个问题在于,这个函数不能正确处理所有类型的参数。当输入参数的类型不是数字或时,尝试将它们相加将会导致运行时错误,所以需要约束

function plusNumber<T extends number>(a: T, b: T): number {  
    return a + b  
}
plusNumber<number>(1,2)

类似的例子还有这种

function getLength<T>(value: T) {
    return value.length
}

编译报错:类型“T”上不存在属性“length”

报错原因:泛型T作为getLength的泛型参数的类型范围大了,某些数据类型是没有length属性,导致无法进行length的访问

可以用泛型约束来修复

function getLength<T extends {length: number}>(value: T) {
    return value.length
}

注意:函数约束是为了让范围的可代表类型的范围缩小,并不是给泛型指定类型。

可迭代的对象,才可以进行对应的数据转换


interface IPrev<U> {
[key:number]:U
}


function createObject<T extends Iterable<any>>(value: T) {
return [...value].reduce((prev:IPrev<U>,current:U,index:number) =>{
prev[index] = current
return prev
},{})}

4. 泛型的联合类型

举个例子

function mergeArr<E> (arr1: E[],arr2:E[]) {
    return [...arr1,...arr2]
}

const arr = mergeArr<number>([1,2,3],['a','b','c'])

类型推断: 根据第一个实参[1,2,3]推断E为number,所以[‘a’,‘b’,‘c’]里面的值为字符串的时候会有编译报错
编译报错:不能将类型“string”分配给类型“number”。

这个时候就可以使用联合类型

type typeValue = string | number

function mergeArr<E> (arr1: E[],arr2:E[]) {
    return [...arr1,...arr2]
}

const arr = mergeArr<typeValue>([1,2,3],['a','b','c'])

三.总结

泛型的好处:

  1. 可以在不明确类型的时候,使用泛型占位
  2. 可以在调用函数是,对函数的参数进行类型的约束

类型参数化是泛型的特征:

  1. 定义时,传入类型参数(泛型)
  2. 调用时,传入实际类型
  • 21
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值