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

TypeScript:创建输入相互依赖的函数的问题求助

解决方案与解释

问题根源

你的代码中,TypeScript将传入的[A1, A1, A2]推断为联合类型数组(typeof A1 | typeof A2)[],而非保留元素顺序的元组类型。这导致loadInstructions的参数被推断为任意数量的A1 | A2联合类型,既不限制参数数量,也无法匹配对应位置的具体类型。同时,原代码未处理非构造函数类型的parsers元素,会导致InstanceType报错。

修正后的代码

class Result {}

function init<P extends readonly any[]>(
  route: string,
  parsers: P,
  loadInstructions: (...data: { 
    [I in keyof P]: P[I] extends new (...args: any[]) => infer Instance 
      ? Instance 
      : P[I] 
  }) => Result
): Result {
  // 模拟解析逻辑:根据parsers生成对应实例/值
  const parsedData = parsers.map((item) => {
    if (typeof item === 'function' && 'prototype' in item) {
      // 假设从JSON字符串解析后构造实例
      return new item();
    }
    return item;
  }) as unknown as { [I in keyof P]: P[I] extends new (...args: any[]) => infer Instance ? Instance : P[I] };

  return loadInstructions(...parsedData);
}

// 测试用例
class A1 { name: string; }
class A2 { address: string; }

// 类型完全匹配的调用
init("/user", [A1, A1, A2], (a: A1, b: A1, c: A2) => {
  return new Result();
});

// 支持非构造函数类型的parsers
init("/config", [A1, "default", 3000], (a: A1, str: string, num: number) => {
  return new Result();
});

关键改进点

  1. 强制元组类型推断
    使用P extends readonly any[]作为泛型约束,让TypeScript将传入的数组字面量推断为只读元组,保留每个元素的具体类型和顺序,而非合并为联合类型数组。

  2. 兼容任意类型的parsers
    通过条件类型P[I] extends new (...args: any[]) => infer Instance ? Instance : P[I]处理所有类型的元素:

    • 如果元素是构造函数,自动提取其实例类型
    • 如果是非构造函数(如字符串、数字),直接使用元素本身的类型
  3. 严格匹配参数数量与类型
    映射后的元组类型作为loadInstructions的剩余参数,确保参数数量、顺序、类型完全对应parsers数组的元素类型,不符合时会直接抛出类型错误。

额外建议

  • 如果需要支持可修改的数组(非只读),可以将泛型约束改为P extends any[],但调用时需要添加as const断言(如[A1, A1, A2] as const),不过会增加调用者的负担,推荐优先使用只读元组方案。
  • 若需要更严格的构造函数校验,可以调整条件类型为P[I] extends new (...args: any[]) => any ? InstanceType<P[I]> : never,但会限制parsers只能传入构造函数类型,不符合你“接受任意类型”的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 15:37:07