如何在TypeScript中定义含可选值但至少一个必填的接口
在TypeScript中实现“至少一个属性必填”的接口
嘿,这个需求完全可以在TypeScript的类型系统层面解决,不用依赖运行时校验!咱们直接看方案:
核心思路:用联合类型替代单一接口
原来的ISearchKey把两个属性都设为可选,导致空对象也能通过类型检查。我们可以把它拆成两个子类型的联合——一个要求name必填(id可选),另一个要求id必填(name可选)。这样TypeScript会强制传入的对象至少匹配其中一个子类型,自然就避免了全空的情况。
实现代码
// 定义联合类型,保证至少有name或id中的一个 type ISearchKey = | { name: string; id?: number } | { id: number; name?: string }; function findItem(search: ISearchKey): Item { // ... 你的业务逻辑 return {} as Item; } // 测试合法情况 findItem({ name: "Alice" }); // ✅ 正常 findItem({ id: 123 }); // ✅ 正常 findItem({ name: "Bob", id: 456 }); // ✅ 正常(两个都填也允许) // 测试非法情况 findItem({}); // ❌ TypeScript报错:类型“{}”不能赋值给类型“ISearchKey”
扩展:有更多公共属性的情况
如果你的搜索参数还有其他可选属性(比如age),可以把公共部分抽出来,用交叉类型合并,让代码更易维护:
// 公共可选属性 type CommonSearchProps = { age?: number; category?: string }; // 联合类型结合公共属性 type ISearchKey = | ({ name: string } & CommonSearchProps) | ({ id: number } & CommonSearchProps); // 测试:可以同时填name和age findItem({ name: "Charlie", age: 30 }); // ✅ 正常
原理说明
联合类型的每个分支都明确了至少一个必填字段,TypeScript的类型检查器会验证传入的对象是否能匹配至少一个分支。空对象{}无法匹配任何一个分支(因为每个分支都要求至少有一个必填属性),所以会直接抛出类型错误,从根源上杜绝了不符合要求的输入。
内容的提问来源于stack exchange,提问作者Gil Epshtain
相关产品推荐
相关产品推荐

