TypeScript 函数重载:多参数与单参数的优雅兼容

我们经常会遇到一种情况,即一个函数需要接收多个参数。然而,随着参数数量的增多,函数的调用和维护都会变得越来越复杂,可读性也会大大降低。那么,有没有一种方法可以同时保持函数的灵活性和可读性呢?

答案是肯定的。在 TypeScript 中,我们可以利用函数重载和高级类型来实现这个目标。具体来说,我们可以设计一个函数,既可以接收一个包含所有参数的对象,也可以接收一系列独立的参数。这样,我们就可以根据实际需求选择最适合的调用方式。

场景分析

首先,让我们看一下初始的函数定义:

typescript 复制代码
export default class OpenAI {
    static async request(
        messages: message[],
        onFinish: (responseText: string, cancel?: boolean) => any,
        onUpdate?: (responseText: string, delta: string) => any,
        onError?: (e: Error) => any,
        functions?: any[],
        closeFn?: MutableRefObject<any>,
        function_call?: any,
        stream: boolean = true,
        extra: {
            model?: string;
            temperature?: number;
            frequency_penalty?: number;
            presence_penalty?: number;
        } = {}
    ) {}
}

这是一个非常典型的多参数函数。它需要接收多个参数,包括 messagesonFinish 等。虽然这样的设计可以提供很大的灵活性,但是随着参数数量的增多,函数调用的复杂性也会增加。例如,当我们需要改变 stream 的值时,我们需要提供所有前面的参数,即使这些参数的值并没有改变。这就导致了代码的冗余,也增加了出错的可能性。

优化方案

为了解决这个问题,我们可以利用 TypeScript 的函数重载和高级类型来设计一个新的函数。这个函数既可以接收一个包含所有参数的对象,也可以接收一系列独立的参数。这样,我们就可以根据实际需求选择最适合的调用方式。

首先,我们定义了一个 RequestOptions 接口,它将所有的参数整合在一个对象中。这样,我们就可以通过传递一个对象来调用函数,而不是传递一系列的参数。这极大地提高了代码的可读性和维护性。

typescript 复制代码
interface RequestExtraOptions {
    model?: string;
    temperature?: number;
    frequency_penalty?: number;
    presence_penalty?: number;
}

interface RequestOptions {
    messages: message[];
    onFinish: (responseText: string, cancel?: boolean) => any;
    onUpdate?: (responseText: string, delta: string) => any;
    onError?: (e: Error) => any;
    functions?: any[];
    closeFn?: MutableRefObject<any>;
    function_call?: any;
    stream?: boolean;
    extra?: RequestExtraOptions;
}

然后,我们定义了一个 MultiRequest 类型,它表示多参数形式的函数。这个类型是一个函数类型,它的参数类型和 RequestOptions 接口中的字段类型一一对应。

typescript 复制代码
type MultiRequest = (
    messages: RequestOptions['messages'],
    onFinish: RequestOptions['onFinish'],
    onUpdate?: RequestOptions['onUpdate'],
    onError?: RequestOptions['onError'],
    functions?: RequestOptions['functions'],
    closeFn?: RequestOptions['closeFn'],
    function_call?: RequestOptions['function_call'],
    stream?: RequestOptions['stream'],
    extra?: RequestOptions['extra']
) => Promise<void>;

接下来,我们定义了一个 isRequestOptionsArr 类型守卫函数,它用来判断传入的参数是否为 RequestOptions 类型的数组。这个函数的返回值是一个类型谓词,它告诉 TypeScript 编译器 args 参数的实际类型。

typescript 复制代码
function isRequestOptionsArr(
    args: [RequestOptions] | Parameters<MultiRequest>
): args is [RequestOptions] {
    return args.length === 1 && typeof args[0] === 'object' && !Array.isArray(args[0]);
}

最后,我们定义了一个新的 request 函数。这个函数接收一个参数数组,然后根据参数的形式分别处理。如果参数是 RequestOptions 类型的数组,我们就直接将其赋值给 options 对象。否则,我们就将参数解构并赋值给 options 对象。

typescript 复制代码
export default class OpenAI {
    static async request(...args: [RequestOptions] | Parameters<MultiRequest>): Promise<void> {
        let options: RequestOptions;

        if (isRequestOptionsArr(args)) {
            // 单参数形式
            options = args[0] as RequestOptions;
        } else {
            // 多参数形式
            options = {
                messages: args[0],
                onFinish: args[1],
                onUpdate: args[2],
                onError: args[3],
                functions: args[4],
                closeFn: args[5],
                function_call: args[6],
                stream: args[7],
                extra: args[8],
            };
        }
        const {
            messages,
            onFinish,
            onUpdate,
            onError,
            functions,
            closeFn,
            function_call,
            stream = true,
            extra = {},
        } = options;
    }
}

这样,我们就实现了一个既可以接收一个包含所有参数的对象,也可以接收一系列独立的参数的函数。这种设计使得函数调用更加灵活和简洁,提供了更好的用户体验和代码可维护性。

结论

通过上述分析,我们可以看出,TypeScript 的函数重载和高级类型为我们提供了一种优雅的解决方案。它们可以使我们的代码更加灵活、易读和可维护。所以,当我们在编程中遇到类似的问题时,不妨尝试使用这种方法来优化我们的代码。

相关推荐
刘发财8 小时前
前端2秒生成500页矢量PDF,rust真的强到没朋友
前端·javascript·rust
郑州光合科技余经理9 小时前
国际版外卖系统:税率字段怎么和订单主流程解耦
android·java·开发语言·前端·后端·php·ai编程
梦想平凡9 小时前
百游棋牌源代码开发搭建教程(十):隔离部署、备份恢复与双端验收
java·前端·javascript·数据库·源代码管理
yume_sibai11 小时前
06-Rust Web 开发实战(Axum 框架 + 数据库 + JWT 认证 + 中间件 + 部署)
前端·数据库·rust
计算机魔术师12 小时前
特朗普上台打给黄仁勋:AI末日论是骗局,我们绝不让它发生
前端
troy12812 小时前
Python 基础语法(八):Web 后端开发、数据分析与可视化、网络爬虫、人工智能 / 大模型应用
前端·python·数据分析
计算机魔术师12 小时前
CEO说要慢下来,黑客说别做梦了——同一篇论文,两种命运
前端
kyriewen13 小时前
我花3天抓了一个幽灵bug,凶手藏在第4层
前端·javascript·程序员
IT_陈寒14 小时前
Java里用Stream.parallel()翻车实录,这性能还不如单线程
前端·人工智能·后端
wangchunyu11414 小时前
JavaScript 零基础入门教程
前端