You need to enable JavaScript to run this app. TypeScript中如何根据返回类型是否含指定属性要求对应参数必填
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中如何根据返回类型是否含指定属性要求对应参数必填

最优实现方案

我们可以通过条件类型合并重复的重载签名,大幅简化类型代码,同时完全保留原有的类型校验规则:

type SelectById = <D extends Record<string, unknown>, K extends keyof D, V extends D[K]>(
  table: string,
  idKey: K,
  idVal: V,
  // 核心逻辑:返回值D包含company_id时参数必填,否则禁止传入
  ...args: 'company_id' extends keyof D 
    ? [company_id: number] 
    : [company_id?: never]
) => Promise<D>

const selectById: SelectById = async (
  table: string,
  idKey: string,
  idVal: unknown,
  company_id?: number
) => {
  if (company_id) {
    return { id: 1, name: "With Company Id", company_id } as unknown as D;
  } else {
    return { id: 2, name: "Without Company Id" } as unknown as D;
  }
};

// 测试用例和原有逻辑完全一致
type FooObjectWithCompany = {
  company_id: number;
  id: number;
  name: string;
};

type BarObjectWithoutCompany = {
  id: number;
  name: string;
};

// 会触发类型错误,符合预期
const thingy: Promise<FooObjectWithCompany> = selectById("footable", "id", 1);
const otherThingy: Promise<BarObjectWithoutCompany> = selectById("bartable", "id", 1, 2);

// 无类型错误,符合预期
const thingyWorking: Promise<FooObjectWithCompany> = selectById("footable", "id", 1, 1);
const otherThingyWorking: Promise<BarObjectWithoutCompany> = selectById("bartable", "id", 1);

方案说明

  • 用剩余参数+条件类型替代两个重复的重载声明,代码量减少近40%,可读性更强
  • 没有冗余的中间类型定义,直接通过'company_id' extends keyof D的判断动态生成参数规则,符合TypeScript类型编程的惯用法
  • 原有类型校验能力完全保留:返回值带company_id时参数必填,不带时禁止传入,完全匹配需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 16:45:05