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 ~

相关推荐
天宇&嘘月1 小时前
web第三次作业
前端·javascript·css
小王不会写code2 小时前
axios
前端·javascript·axios
发呆的薇薇°3 小时前
vue3 配置@根路径
前端·vue.js
luckyext3 小时前
HBuilderX中,VUE生成随机数字,vue调用随机数函数
前端·javascript·vue.js·微信小程序·小程序
小小码农(找工作版)3 小时前
JavaScript 前端面试 4(作用域链、this)
前端·javascript·面试
前端没钱4 小时前
前端需要学习 Docker 吗?
前端·学习·docker
前端郭德纲4 小时前
前端自动化部署的极简方案
运维·前端·自动化
海绵宝宝_4 小时前
【HarmonyOS NEXT】获取正式应用签名证书的签名信息
android·前端·华为·harmonyos·鸿蒙·鸿蒙应用开发
码农土豆4 小时前
chrome V3插件开发,调用 chrome.action.setIcon,提示路径找不到
前端·chrome
鱼樱前端5 小时前
深入JavaScript引擎与模块加载机制:从V8原理到模块化实战
前端·javascript