Skip to content

泛型

简介

泛型是一种用于定义泛型数据类型的机制。

泛型允许创建通用的函数和类,这些函数和类可以处理不同类型的数据。简单来说就是:

  • 可以定义一个函数或类,参数使用对象类型,但在调用函数时传入具体类型。
  • 泛型提供了一种方法来表示函数或类中的类型,但是还没有实际指定这个类型。
  • 调用它的时候,可以指定具体类型的参数。

示例

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>

Released under the MIT License.