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
相关产品推荐
相关产品推荐

