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

TypeScript中readQuery函数根据fields参数动态返回类型的实现

实现方案:泛型+条件类型+字面量推断

直接用泛型结合条件类型就能精准约束返回类型,比重载更简洁且类型推断更准确。核心是让fields参数的类型被推断为具体的键字面量数组,再通过条件类型动态生成返回类型。

步骤1:定义基础类型(示例)

先给出ERPTypes的示例结构,方便后续演示:

// 示例ERP实体类型
type ERPTypes = {
  User: { id: number; name: string; email: string };
  Order: { orderId: string; amount: number; status: string };
};

步骤2:定义函数的泛型参数与条件类型

函数需要两个泛型:

  • T:指定操作的ERP实体类型(比如"User"或"Order")
  • K:可选,指定fields的具体键字面量,默认是keyof ERPTypes[T]

通过条件类型判断是否传入了fields,动态决定返回类型:

type ReadQueryReturn<T extends keyof ERPTypes, K extends keyof ERPTypes[T]> =
  K extends never
    ? Promise<ERPTypes[T][]>
    : Promise<Pick<ERPTypes[T], K>[]>;

步骤3:实现函数并约束参数

函数参数要让TypeScript能推断出K的具体字面量类型,所以fields需要定义为readonly K[](用readonly确保字面量类型不被拓宽):

async function readQuery<
  T extends keyof ERPTypes,
  K extends keyof ERPTypes[T] = keyof ERPTypes[T]
>(payload: {
  entity: T;
  fields?: readonly K[];
  // 其他业务参数可在此添加
}): ReadQueryReturn<T, K> {
  // 实际业务逻辑示例:调用接口获取数据
  const rawData = await fetch(`/api/${payload.entity}`).then(res => res.json());
  
  if (payload.fields) {
    return rawData.map(item => {
      const pickedItem: Partial<Pick<ERPTypes[T], K>> = {};
      payload.fields.forEach(key => {
        pickedItem[key] = item[key];
      });
      return pickedItem as Pick<ERPTypes[T], K>;
    }) as ReadQueryReturn<T, K>;
  }
  
  return rawData as ReadQueryReturn<T, K>;
}

测试验证

调用时TypeScript会自动根据是否传入fields推断返回类型:

// 未传fields,返回Promise<User[]>
const allUsers = await readQuery({ entity: "User" });
allUsers[0].id; // ✅ 正常访问所有属性

// 传fields,返回Promise<Pick<User, "id" | "name">[]>
const partialUsers = await readQuery({ entity: "User", fields: ["id", "name"] });
partialUsers[0].id; // ✅ 可访问id、name
partialUsers[0].email; // ❌ 类型报错,email不在返回类型中

为什么比重载更优?

重载需要手动编写多个函数签名,且无法自动捕获fields的具体键字面量(除非每个重载都手动指定键,扩展性极差)。而泛型+条件类型的方案能自动推断fields的具体键,同时动态生成返回类型,代码更简洁,类型约束更精准。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 15:22:23