一、泛型的概述
“泛”就是广泛的意思,”型”就是数据类型。顾名思义,泛型就是适用于多种数据类型的一种类型。
它能够帮助我们构建出复用性更强的代码。
假如有如下函数:
function sum(num: number): number {
return num
}
此时函数的参数和返回值都必须是number
类型的。
但是其它类型的数据,比如string
、boolean
或者自定义的Teacher
等类型就没有办法使用这个函数。
虽然any可以解决这个问题,但是函数参数和返回值定义为any的时候,具体的类型信息就已经丢失了。
比如传入的是一个number
,那么我们希望返回的并不是any
类型,而是number
类型。
所以,我们需要在函数中可以捕获到参数的类型是number
,并且同时使用它来作为返回值的类型。
因此需要在这里使用一种特性的变量 – 类型变量(type variable
),它作用于类型,而不是值!
二、泛型的基本使用
2.1 泛型函数示例
在定义一个函数时,不决定这些参数的类型,而是让调用者以参数的形式告知函数参数应该是什么类型。
function sum<T>(num: T): T {
return num
}
我们可以把Type
看做额外的一个参数,把类型参数化。
它可以做到, 在定义这个函数时, 不决定这些参数的类型, 而是让调用者以参数的形式告知, 这里的函数参数应该是什么类型。
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")
三、常用的泛型名称
开发中可能会看到一些常用的名称,不同的名称会有不同语义化意义。
-
T
:Type
的缩写,类型 -
K、V
:key
和value
的缩写,键值对 -
E
:Element
的缩写,元素 -
O
:Object
的缩写,对象
四、传入多个泛型
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"]
七、泛型约束
有时候希望传入的类型具有某些共性,但是这些共性可能不是在同一种类型中。
比如string
和array
都是有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
后面的类型或者子类型。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/116468.html