You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现TypeScript类型安全的多函数调用targetFunction

问题描述

我正在构建一个库,需要实现一个targetFunction函数,使其能与以下接口实现对象交互:

const testInterfaceImpl = {
    testSN: (a: string, n: number) => { return "" },
    testN: (n: number) => { return },
    test: () => { return 0 }
}

该函数的调用示例如下:

const [stringResult0] = targetFunction([ ["testSN", "", 6] ])
const [stringResult0, voidResult1, stringResult2] = targetFunction([ ["testSN", "john", 5], ["test"], ["testSN", "doe", 7] ])
const [numberResult0, _] = targetFunction([ ["testN", 5], ["testSN", 999999] ]) // TS 应该在这里报错,因为["testSN", 5]参数不符合类型

具体需求:

  • 函数需能推断对象的可用函数名、对应参数及返回类型
  • 支持传入多个包含函数名和对应参数的可变元组
  • 返回与传入参数长度一致的带类型结果数组
  • 错误提示或智能感知需显示所选函数的参数类型

我已实现支持单次调用的类型安全版本,但多函数调用版本存在类型校验失效问题,部分错误调用无法被TypeScript检测到,需要解决方案。

解决方案

通过元组映射和条件类型可实现多调用场景的类型安全,核心是对每个调用元组单独做类型校验,并映射出对应返回类型数组:

// 定义合法的调用元组类型:[函数名, ...参数列表]
type CallEntry<T extends Record<string, (...args: any[]) => any>> = {
    [K in keyof T]: [K, ...Parameters<T[K]>]
}[keyof T];

// 映射调用元组数组到对应的返回类型数组
type CallResult<T extends Record<string, (...args: any[]) => any>, E extends CallEntry<T>[]> = {
    [I in keyof E]: E[I] extends [infer K extends keyof T, ...infer Args extends Parameters<T[K]>]
        ? ReturnType<T[K]>
        : never
};

// 实现targetFunction
function targetFunction<T extends Record<string, (...args: any[]) => any>, E extends CallEntry<T>[]>(
    entries: [...E],
    impl: T = testInterfaceImpl as T
): CallResult<T, E> {
    return entries.map(([fnName, ...args]) => {
        return impl[fnName](...args as any);
    }) as CallResult<T, E>;
}

// 测试用例
const testInterfaceImpl = {
    testSN: (a: string, n: number) => { return "" },
    testN: (n: number) => {},
    test: () => { return 0 }
}

// 合法调用
const [stringResult0] = targetFunction([ ["testSN", "", 6] ])
const [stringResult0_2, voidResult1, stringResult2] = targetFunction([ ["testSN", "john", 5], ["test"], ["testSN", "doe", 7] ])

// 非法调用:TS会报错,testSN的第一个参数应为string而非number
const [numberResult0, _] = targetFunction([ ["testN", 5], ["testSN", 999999] ])

实现说明

  1. CallEntry<T>:生成所有符合接口定义的调用元组类型,确保函数名和参数的合法性。
  2. CallResult<T, E>:对传入的调用元组数组做逐位映射,保证返回数组的类型与调用顺序严格对应。
  3. [...E]参数:利用TypeScript可变元组推断能力,让编译器准确识别每个调用元组的具体类型,避免联合类型导致的校验失效。
  4. 类型断言:args as any是因为TypeScript无法自动推导args与目标函数参数的精确匹配,但外层类型约束已确保传入参数合法,无运行时风险。

内容的提问来源于stack exchange,提问作者Peter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 00:10:34