TS思考 - 函数重载

TS思考系列又与大家准时见面了~(其实是我没有别的系列可以写)

今天来看一看我一直搞不懂的,函数重载

什么时候要用到函数重载呢?

其实我在看官网例子的时候,一头雾水

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

const userList: User[] = [
    { id: 1, name: "小明", age: 20, grades: 89 },
    { id: 2, name: "小明", age: 20, grades: 89 },
    { id: 3, name: "小明", age: 20, grades: 89 },
    { id: 4, name: "小明", age: 20, grades: 89 }
]


function getUserInfo(value: number): User | undefined
function getUserInfo(value: string): User[]
function getUserInfo(value: number | string): User | User[] | undefined {
    if (typeof value === 'number') {
        return userList.find(item => item.id === value)
    } else {
        return userList.filter(item => item.grades === Number(value))
    }
}



function getUserInfo1(value:number|string) {
    if(typeof value==='number'){
        return userList.find(item=>item.id===value)
    }else{
        return userList.filter(item=>item.grades===Number(value))
    }
}

getUserInfo('1');
getUserInfo1('1')

先看看这个例子,我就想实现一个函数,他能做到这样的效果

先做准备工作



这个时候肯定会想到类型收紧

function getUserInfo(value: number | string) {
    if (typeof value === 'number') {
        return userList.find(item => item.id === value)
    } else {
        return userList.filter(item => item.grades === Number(value))
    }
}

这个函数没有问题,能实现我们想要的效果,但是也有些美中不足

const result = getUserInfo(1);

getUserInfo 这个函数的返回值被推断成了 User | User[] | undefined

抛开 undefined 不谈,我们其实在写代码的时候是知道不同输入类型对应的返回值类型的。

特别是像例子中这样拿着 result 返回值还要做后续操作的。

这个时候函数重载就派上用场了,我们可以定义两个函数签名,它们的输入将会决定它们的输出:

function getUserInfo(value: number): User | undefined
function getUserInfo(value: string): User[]
function getUserInfo(value: number | string) {
    if (typeof value === 'number') {
        return userList.find(item => item.id === value)
    } else {
        return userList.filter(item => item.grades === Number(value))
    }
}

const result = getUserInfo(1);
const result2 = getUserInfo('2');

可以看到重载后,返回值的类型是可以明确推断出来的。

重载的顺序

TypeScript 重载的过程是,拿传入的参数和重载的方法签名列表中由上往下逐个匹配,直到找到一个完全匹配的函数签名,否则报错。所以推荐的做法是将签名更加具体的重载放上面,不那么具体的放后面。

interface ReadonlyArray<T> {
  reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T;
  reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, initialValue: T): T;
  reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U;
}

const A = [1, '2', 3]
const str: string = A.reduce((str, a) => `${str} ${a.toString()}`, '')

我们来回顾一下为什么会报错:

但是如果第三个签名 和 第二个签名交换顺序,就可以,来一起看一下交换后匹配过程

所以函数重载的签名顺序也有学问哈哈哈。

参考