TypeScript细碎知识点:TS中的函数重载,方法重载,构造器重载

理解重载

用于实现不同参数输入并且对应不同参数输出的函数,在前面定义多个重载签名,一个实现签名,一个函数体构造,重载签名主要是精确显示函数的输入输出,实现签名主要是将所有的输入输出类型做一个全量定义,防止TS编译报错,函数体就是整个整个函数实现的全部逻辑。

函数重载

🌰应用例子:

一个班级有很多学生,老师要查询学生的用户信息,如果是输入数字就通过排名(id)去匹配,输入的是字符串就通过分数(grades)去匹配,用TS模拟这种情况。

首先定义用户类型

type User = {
    id: number,
    name: string,
    age: number,
    grades: number
}

班级用户信息数据

const userList: User[] = [
    { id: 1, name: '小明', age: 20, grades: 98 },
    { id: 2, name: '小李', age: 24, grades: 88 },
    { id: 3, name: '小张', age: 21, grades: 99 },
    { id: 4, name: '小王', age: 28, grades: 78 },
]

1.普通实现思路

通过联合类型来做输入定义,输出定义。输入number是(id)是唯一的名次,使用find;输入string是(grades)可能有重复的,使用filter。

function getUserInfo(value: number | string): User | User[] {
    if (typeof value === 'string') {
        return userList.find(item => item.id === value) /*error: 不能将类型“User | undefined”分配给类型“User | User[]”。 
                                                                 不能将类型“undefined”分配给类型“User | User[]”。*/
    } else {
        return userList.filter(item => item.grades === value)
    }
}

这样定义TS会报一个异常

error:不能将类型“User | undefined”分配给类型“User | User[]”。不能将类型“undefined”分配给类型“User | User[]”。

原因切到底层find方法源码,发现是find可能返回的undefined类型

⭕️ 解决方式很简单,返回类型再联合一个undefined即可解决。

缺点:缺点很明确,都是通过联合类型输入输出,明明知道number输入一定返回User,string输入一定返回User[],这样返回不明确输入什么返回什么,很多时候我们看方法的定义的时候就想看输入啥返回啥,更好的判定类型,为了解决这个函数重载出现了

2.函数重载实现思路

TS的函数重载主要分为 “多个重载签名 实现签名 函数体”

简单理解来看实现签名主要是之前普通实现思路的情况,TS编译的时候检查所有类型和函数体中的对比检查是否存在。实现签名和函数体检查通过后,执行函数的时候实际上是某个重载签名+函数体,跳过了实现签名。

🔔:通过鼠标点击实际调用方法getUserInfo(2),command+鼠标右键,他会自动解析跳转到number这个重载签名上面去,很直观的知道如何调用的。

需求变更: 现在查询相同分数太多,老师输入string想添加一个变量count用于控制查询数量。

修改步骤:第二个重载签名和实现签名添加count定义,函数体书写count逻辑,但是TS报出一下错,意思是实现签名传了两个值,第一个重载签名却只有一个值。

解决办法:那么只有在实现签名增加一个count默认值即可。

方法重载

方法重载和函数重载其实差不多,还是方法重载是放在类里面的

🌰应用例子:

简单封装一个数组,使数组更加好用,通过index删除返回index,通过object删除返回object

class ArrayEN {
    constructor(public arr: object[]) { } 

    get(index: number) {
        return this.arr[index];
    }

    delete(value: number): number;
    delete(value: object): object;
    delete(value: number | object): number | object {
        this.arr = this.arr.filter((item, index) => {
            if (typeof value === "number") {
                return value !== index;
            } else {
                return value !== item;
            }
        });
        return value;
    }
}

构造器重载

先来理解构造器constructor的原理,构造器是没有返回值的,他会隐式返回一个this,这个this会分配给new对象的左边的变量,至此所有的this都是指向的当前正在使用的对象。

构造器重载和函数重载使基本相同,主要区别是:

⏰ TS 类构造器重载签名和实现签名都不需要管理返回值,TS 构造器是在对象创建出来之后,但是还没有赋值给对象变量之前被执行,一般用来给对象属性赋值。

🌰应用例子:

现在要求算一个图片的面积,这个图形可能是传参可以是对象也可能是长宽

interface OJType {
    width?: number,
    heigth?: number
}

class Graph {
    public width: number;
    public heigth: number;

    constructor(width?: number, height?: number)
    constructor(side?: OJType)
    constructor(v1: any, v2?: any) {
        if (typeof v1 === 'object') {
            this.width = v1.width;
            this.heigth = v1.height;
        } else {
            this.width = v1;
            this.heigth = v2;
        }
    }

    getArea() {
        const { width, heigth } = this
        return width * heigth
    }
}

const g = new Graph(10, 10)
console.log(g.getArea());

主要实现思路:

通过构造器将类型定义出来,首先是带有长宽对象的类型,这里才用接口的形式定义,然后就是width,heihgt的number类型,最后简单的通过typeod判断对象类型然后进行赋值,综上发现不管是函数重载,方法重载,构造器重载都是异曲同工之妙,只是需要注意使用场景就行。

posted on 2024-07-08 11:08  梁飞宇  阅读(188)  评论(0)    收藏  举报