泛型
简介
泛型是一种用于定义泛型数据类型的机制。
泛型允许创建通用的函数和类,这些函数和类可以处理不同类型的数据。简单来说就是:
- 可以定义一个函数或类,参数使用对象类型,但在调用函数时传入具体类型。
- 泛型提供了一种方法来表示函数或类中的类型,但是还没有实际指定这个类型。
- 在调用它的时候,可以指定具体类型的参数。
示例
typescript
// 动态类型
// function rarrot(a:number,b:number):Array<number>{
// return [a,b]
// }
// function rarrots(a:string,b:string):Array<string>{
// return [a,b]
// }
// 对于以上重复代码可以使用以下泛型即可
function rarrot<T>(a: T, b: T): Array<T> {
return [a, b]
}
rarrot(1, 2)
rarrot('1', '2')
// 将类型设置为T,即可动态设置类型
type A<T> = string | number | T
let a: A<null> = null
// 接口泛型
interface Data<T> {
msg: T
}
let data: Data<string> = {
msg: '今天你开心吗'
}
// 可以定义两个泛型,可以提前提供类型,后面更改会自动推断类型,如下
function add<T = number, K = number>(a: T, b: K): Array<T | K> {
return [a, b]
}
// 编译器会自动推断类型
add(1, '1')
模拟axios发送请求
typescript
const axios = {
// get方法支持泛型,接受一个URL
get<T>(url: string):Promise<T> {
// Promise接收两个参数
return new Promise((resolve, reject) => {
// 利用XMLHttpRequest进行调接口
let xhr: XMLHttpRequest = new XMLHttpRequest()
xhr.open('GET', url)//对请求的url进行获取
// 监听状态变化,有五个状态码:0,1,2,3,4,到4时即为成功
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
// xhr.responseText返回为一个字符串
// 需要通过JSON.parse转换成一个对象,才使用resolve进行返回
resolve(JSON.parse(xhr.responseText))
}
}
// 没有东西进行发送,但一定要写,否则为无效的请求
xhr.send(null)
})
}
}
interface Data{
message:string
code:number
}
axios.get<Data>('data.json').then(res=>{
console.log(res)
})
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>
json
{
"message":"成功",
"code":200
}
泛型约束
泛型约束为只能为number类型:
typescript
// 在类型后面加上extends,后再写一个约束的类型
function add<T extends number>(a:T,b:T){
return a + b
}
add(1,2)
使用接口去定义约束类型,以下代码中只有含有length属性才可以传入fn函数中:
typescript
interface Len{
length:number
}
function fn<T extends Len>(a:T){
a.length
console.log("🚀 ~ file: index.ts:14 ~ a.length:", a.length)
}
fn('123456')//🚀 ~ file: index.ts:14 ~ a.length: 6
fn([1,2,3])//🚀 ~ file: index.ts:14 ~ a.length: 3
let le={
length:5
}
fn(le)//🚀 ~ file: index.ts:14 ~ a.length: 5
使用keyof可以将约束类型定义为对象的属性,例如:
typescript
let obj={
name:'rarrot',
sex:'女'
}
function ob<T extends object,k extends keyof T>(obj:T,key:k){
return obj[key]
}
// 先传入obj给T,T的约束类型为object,传入obj是没问题的,
// 此时k的约束就相当于extends keyof obj,其约束类型为"name"|"sex"
// 若此时第二个传入的参数不是name或者sex,则会报错
ob(obj,'name')
// 使用keyof,以下给出解释:
// 不加keyof时,其类型为:
/*
type key = {
name: string;
sex: string;
}
*/
// 加keyof后,其类型为"name"|"sex"
type key =keyof typeof obj
实现接口为类型时将其中的所有属性设置为可选,也可以设置为只读readonly,还有其余也可以扩展:
typescript
interface Data{
name:string
age:number
sex:string
}
// for in语法 for(let key in obj)
type Options<T extends object>={
// T为Data,
// T[key]为string,number和string,
// keyof T为name,age和sex
// 对应的[key in keyof T]即为 name age sex
// 会循环对应的原因为[key in ...]是一个类型迭代器
[key in keyof T]?:T[key]
// 设置为只读为readonly \[key in keyof T\]:T\[key\]
}
/*
type B = {
name?: string | undefined;
age?: number | undefined;
sex?: string | undefined;
}
*/
type B=Options<Data>