如何实现TypeScript中对象的多个字段同时必填或同时缺失
如何实现TypeScript中对象的多个字段同时必填或同时缺失
嗨,我来帮你搞定这个问题~你遇到的其实是TypeScript联合类型的一个常见“小漏洞”:原来的写法里,UntitledProps | TitledProps会让TypeScript默认允许你传额外的属性(比如只传title),因为它觉得这个对象可以匹配UntitledProps分支(TypeScript会忽略对象字面量的额外属性,除非你明确禁止),所以没法触发你想要的错误提示。
这里给你一个最直观的解决方案,通过never类型来强制字段的“绑定关系”:
import React from "react"; // 先定义基础的公共属性 interface BaseProps { id: string; } // 情况1:完全没有title和icon(用never禁止这两个字段有有效值) type UntitledProps = BaseProps & { title?: never; icon?: never; }; // 情况2:同时拥有title和icon(两个字段都必填) type TitledProps = BaseProps & { title: string; icon: string; }; // 最终的Props类型是两种情况的联合 type Props = UntitledProps | TitledProps; function Component(props: Props) { return <h1>OK</h1>; } // ✅ 正常情况:符合预期,不会报错 const a = <Component id="id" />; const b = <Component id="id" title="title" icon="icon" />; // ❌ 现在这两个会触发你想要的错误,完美! const c = <Component id="id" title="title" />; const d = <Component id="id" icon="icon" />;
原理解释
当我们把title?: never和icon?: never加到UntitledProps里时,TypeScript会明确知道:在这个分支下,title和icon不仅是可选的,而且只能是undefined(或者完全不写)——因为never类型没有任何有效值。
这样一来,当你只传title或者只传icon时,这个对象既不属于UntitledProps(因为有了非undefined的title/icon,违反了never的要求),也不属于TitledProps(因为缺了另一个必填字段),自然就会抛出你预期的错误。
额外扩展:用判别式字段实现(可选)
如果你能接受多传一个标记字段,也可以用判别式的写法,比如加个hasTitle来区分两种状态:
import React from "react"; interface BaseProps { id: string; } type Props = // 无标题图标分支 (BaseProps & { hasTitle: false }) // 有标题图标分支(同时必填) | (BaseProps & { hasTitle: true; title: string; icon: string }); function Component(props: Props) { return <h1>OK</h1>; } // ✅ 正常使用 const a = <Component id="id" hasTitle={false} />; const b = <Component id="id" hasTitle={true} title="title" icon="icon" />; // ❌ 缺字段会报错 const c = <Component id="id" hasTitle={true} title="title" />;
不过这种写法需要额外传hasTitle,如果你想保持API的简洁,第一种方法显然更合适~
内容来源于stack exchange
相关产品推荐
相关产品推荐

