TypeScript 函数重载 -> 箭头函数方式 报错处理;

函数重载

最近在读阮一峰老师的 TS 文档教程,遇到了 函数重载;然后自己摸索了一下 函数重载 相关知识,但是我想着箭头函数也是函数,能不能做函数重载呢?然后我就试了试,并遇到了一些报错;下面是我 对 箭头函数 做 函数重载报错的处理方式;供大家参考;

因自己理解的也不是很深,有什么错误的地方还请大佬指正;万分感谢 🙏


什么是函数重载

有些函数可以接受不同类型或不同个数的参数,并且根据参数的不同,会有不同的函数行为。这种根据参数类型不同,执行不同逻辑的行为,称为函数重载(function overload)。

ts 复制代码
reverse('abc');//cba
reverse([1,2,3]);// [3,2,1]

上面的reverse()可以将参数颠倒输出。参数可以是字符串,也可以是数组;

这意味着,该函数内部有处理字符串和数组的两套逻辑,根据参数类型的不同,分别执行对应的逻辑。这就叫"函数重载"。

TypeScript 对于"函数重载"的类型声明方法是,逐一定义每一种情况的类型。

ts 复制代码
function reverse(str: string): string; 
function reverse(arr: any[]): any[];

上面示例中,分别对函数reverse()的两种参数情况,给予了类型声明。但是,到这里还没有结束,后面还必须对函数reverse()给予完整的类型声明。

ts 复制代码
function reverse(str: string): string;
function reverse(arr: any[]): any[];
function reverse(stringOrArray: string | any[]): string | any[] {
  if (typeof stringOrArray === "string")
    return stringOrArray.split("").reverse().join("");
  else return stringOrArray.slice().reverse();
}

有一些编程语言允许不同的函数参数,对应不同的函数实现。但是,JavaScript 函数只能有一个实现,必须在这个实现当中,处理不同的参数。因此,函数体内部就需要判断参数的类型及个数,并根据判断结果执行不同的操作。

ts 复制代码
function add(x: number, y: number): number;
function add(x: any[], y: any[]): any[];
function add(x: number | any[], y: number | any[]): number | any[] {
  if (typeof x === "number" && typeof y === "number") {
    return x + y;
  } else if (Array.isArray(x) && Array.isArray(y)) {
    return [...x, ...y];
  }

  throw new Error("wrong parameters");
}

上面示例中,函数add()内部使用if代码块,分别处理参数的两种情况。

注意,重载的个别类型描述与函数的具体实现之间,不能有其他代码,否则报错。

以上就是阮老师函数重载的描述以及示例;


那么看完这个示例我就想着,能不能把 函数声明式改为箭头函数的方式;于是我就改了改,代码如下:

ts 复制代码
  type Adds = {
        (x: number, y: number): number;
        (x: any[], y: any[]): any[];
    };
    
   const Add_: Adds = (x: number | any[], y: number | any[]): number | any[] => {
        if (typeof x === 'number' && typeof y === 'number') {
            return x + y;
        } else if (Array.isArray(x) && Array.isArray(y)) {
            return [...x, ...y];
        }

        throw new Error('warning parameters for add');
    }; 

结果就报错了:

报错信息:

不能将类型"(x: number | any[], y: number | any[]) => number | any[]"分配给类型"Adds"。

不能将类型"number | any[]"分配给类型"number"。

不能将类型"any[]"分配给类型"number"。

于是我就去网上搜 相关问题 及报错信息;零零散散 不太全面;有的是说把返回值设为 any ;哎!确实不报错了哈;

ts 复制代码
 type Adds = {
        (x: number, y: number): number;
        (x: any[], y: any[]): any[];
    };
    
   const Add_: Adds = (x: number | any[], y: number | any[]): any => {
        if (typeof x === 'number' && typeof y === 'number') {
            return x + y;
        } else if (Array.isArray(x) && Array.isArray(y)) {
            return [...x, ...y];
        }

        throw new Error('warning parameters for add');
    }; 

但是这样的话就失去了 ts 的意义;于是我又开始对此问题进行钻研,终让我找到了答案;


报错原因

这个错误是由于 TypeScript 在函数类型的兼容性检查中发现了不匹配的问题。在你的代码中,定义了一个类型Adds,它是一个函数类型,接受两个参数并返回一个值。但是,当你尝试将实际的函数Add_分配给Adds类型时,TypeScript 检测到了类型不匹配的情况。 具体来说,你的 Add_ 函数声明返回类型是 number | any[],而 Adds 类型的第二个签名期望返回类型是 any[]。这导致了类型不一致的错误。

说一下我对该段文字的理解:

首先就是 我定义的类型别名type,它是一个函数类型,接受两个参数并返回一个值。但是,当我将函数Add_分配给Adds类型时,TypeScript 检测到了类型不匹配的情况。 就是说 我定义的两个函数的返回值不一致,而我的 add_函数的返回值是 number|any[]; 我定义的 type 第一个函数规定的返回值是 number,第二个参数的返回值是any[]Add_ 函数声明返回类型是 number | any[],而 Adds 类型的第二个签名期望返回类型是 any[]。所以造成了类型不一致的错误;

ts 复制代码
    type Adds1 = {  // 两个函数规定的返回值最终都是 number
        (x: number, y: number): number; // 函数签名     (x: number, y: number) => number
        (x: any[], y: any[]): number;   // 函数签名     (x: any[], y: any[])   => number;
    }
    const Add_1: Adds1 = (x: number | any[], y: number | any[]) => { 
    //function(x: number | any[], y: number | any[]): number(Add_1函数我没有规定返回值类型,类型推断返回值的类型为 number)
        if (typeof x === 'number' && typeof y === 'number') {
            return x + y; // number
        } else if (Array.isArray(x) && Array.isArray(y)) {
            return 1; // number
        }

        throw new Error('warning parameters for add');
    };

以上代码就不报错了,我把type里的两个函数的定义的返回值都规定成了number,也就是说这两个函数的签名期望得到类型都是number,而Add_1 函数的返回值类型也是 number。 类型都一致了,所以不报错了;

问题解决

了解了报错原因之后,想要解决以上的错误信息也很简单,你需要确保 Add_ 函数的返回类型与 Adds 类型的每个签名相匹配。在这里,你可以使用类型断言来明确告诉 TypeScript,Add_1 函数的返回类型是 number | any[],而不是 TypeScript 推断出的类型

可能解释的不是很好;


(根据自己的理解)代码演示:

ts 复制代码
type Adds1 = {  
    (x: number, y: number): number;
    (x: any[], y: any[]): number; 
}
const Add_1: Adds1 = (x: number | any[], y: number | any[]) => {
    if (typeof x === 'number' && typeof y === 'number') {
        return x + y; // number
    } 
    // 这里把 else  if 注一下;
    // else if (Array.isArray(x) && Array.isArray(y)) {
    //     return [...x,...y]; 
    // }

    throw new Error('warning parameters for add');
};

此时 add_1 函数的第一个判断条件成立;add_1函数 返回值类型经过 TypeScript 的类型推断可以得出:

function(x: number | any[], y: number | any[]): number

如果提前规定了 add_1 函数的返回值的类型,如果不是 number类型就会报错;

以下代码就是 TypeScript 类型推断的返回值类型add_1 函数的返回值类型 一致,所以不会报错;

ts 复制代码
type Adds1 = {
    (x: number, y: number): number; 
    (x: any[], y: any[]): number; 
}
const Add_1: Adds1 = (x: number | any[], y: number | any[]):number => { 
    if (typeof x === 'number' && typeof y === 'number') {
        return x + y; // number
    } 

    // else if (Array.isArray(x) && Array.isArray(y)) {
    //     return [...x,...y]; 
    // }

    throw new Error('warning parameters for add');
};
Add_1(1, 1);

此时 add_1 函数的第一个判断条件成立;add_1函数 返回值类型经过 TypeScript 的类型推断可以得出:

function(x: number | any[], y: number | any[]): number

这段代码就是 TypeScript 类型推断的返回值类型add_1 函数的返回值类型 不一致,导致的报错;

ts 复制代码
type Adds1 = {
    (x: number, y: number): number; 
    (x: any[], y: any[]): number;
}
const Add_1: Adds1 = (x: number | any[], y: number | any[]):number|any[] => { 
    if (typeof x === 'number' && typeof y === 'number') {
        return x + y; // number
    } 

    // else if (Array.isArray(x) && Array.isArray(y)) {
    //     return [];
    // }

    throw new Error('warning parameters for add');
};

也就是说 条件无论真假,类型推断的返回值一定不是 number|any[] 类型,要么 number 要么 any[]


最终代码如下:

ts 复制代码
    type Adds = {
        (x: number, y: number): number;
        (x: any[], y: any[]): any[];
    }

    const Add_: Adds = ((x: number | any[], y: number | any[]): number | any[] => {
        if (typeof x === 'number' && typeof y === 'number') {
            return x + y;
        } else if (Array.isArray(x) && Array.isArray(y)) {
            return [...x, ...y];
        }

        throw new Error('warning parameters for add');
    }) as Adds;

不建议使用箭头函数做函数重载:

如果你真的需要使用箭头函数,可以考虑合并函数签名的方式,而不是使用函数重载。下面是一个使用箭头函数的例子

ts 复制代码
type AType = number | any[];
type Adds = (x: AType, y: AType) => number | (AType)[];

const Add_: Adds = (x: AType, y: AType): number | (AType)[] => {
    if (typeof x === 'number' && typeof y === 'number') {
        return x + y;
    } else if (Array.isArray(x) && Array.isArray(y)) {
        return [...x, ...y];
    }

    throw new Error('warning parameters for add');
};

console.log(Add_([1, 2, 3], ['a', 'b', 'c']));

箭头函数不太适合函数重载,因为箭头函数无法像普通函数那样进行函数重载.

箭头函数在JavaScript中确实是一个非常方便的特性,它提供了一种简洁的语法来编写函数。然而,它们并不适合所有的场景,特别是在函数重载的情况下。

首先,箭头函数没有自己的this 。它们从封闭的作用域中继承this值。这可能会导致在需要使用特定this上下文的方法中出现问题,尤其是在构造函数中使用箭头函数时,会抛出异常,因为箭头函数不能作为构造函数。

其次,箭头函数不支持对象的arguments对象 。在传统的函数中,可以使用arguments对象来访问传递给函数的所有参数,但是在箭头函数中,这个对象是不可用的。

最后,箭头函数的重载解析与普通函数不同。由于箭头函数的语法限制,它们在重载时可能不会按照预期工作。例如,箭头函数体内的表达式必须用括号包裹,否则可能会导致代码逻辑错误。

综上所述,虽然箭头函数在很多情况下都非常有用,但在需要函数重载的场景中,它们的一些限制使得它们不是最佳选择。在这些情况下,使用传统的函数声明可能是更好的选择。

附:

阮一峰 TypeScript 教程 这是一篇非常好的文档;

👋 bye ~

相关推荐
zhanghaisong_201514 分钟前
Caused by: org.attoparser.ParseException:
前端·javascript·html·thymeleaf
Eric_见嘉17 分钟前
真的能无限试(白)用(嫖)cursor 吗?
前端·visual studio code
DK七七1 小时前
多端校园圈子论坛小程序,多个学校同时代理,校园小程序分展示后台管理源码
开发语言·前端·微信小程序·小程序·php
老赵的博客1 小时前
QSS 设置bug
前端·bug·音视频
Chikaoya1 小时前
项目中用户数据获取遇到bug
前端·typescript·vue·bug
南城夏季1 小时前
蓝领招聘二期笔记
前端·javascript·笔记
Huazie1 小时前
来花个几分钟,轻松掌握 Hexo Diversity 主题配置内容
前端·javascript·hexo
NoloveisGod1 小时前
Vue的基础使用
前端·javascript·vue.js
GISer_Jing1 小时前
前端系统设计面试题(二)Javascript\Vue
前端·javascript·vue.js
海上彼尚2 小时前
实现3D热力图
前端·javascript·3d