如何在TypeScript中强制实现属性间的依赖关系
解决TypeScript中React组件属性间的依赖关系问题
要实现React组件属性间的依赖(比如按钮文本和点击处理器必须同时存在或同时不存在),我们先分析原有代码的问题,再给出可行方案。
原有代码的错误点
泛型约束与映射类型不匹配
原有代码中PropertyName允许为undefined,当传入T为字符串但PropertyName为undefined时,第二个映射类型{ [K in PropertyName]: () => void }会因K的类型无效被忽略,导致只生成文本属性。else分支属性名错误
在T extends string的else分支中,代码写的是{ T?: undefined; PropertyName?: undefined; },这里的T和PropertyName是泛型参数名,并非实际要生成的属性名,最终会创建名为T和PropertyName的属性,完全不符合需求。
正确实现方案
通过联合类型明确两种合法状态:要么两个属性都必填,要么两个都可选且值只能为undefined(或完全不出现)。
定义关联属性类型
type LinkedProps<TextProp extends string, HandlerProp extends string> = // 状态1:文本属性和处理器属性都必填 { [K in TextProp]: string } & { [K in HandlerProp]: () => void } // 状态2:文本属性和处理器属性都可选且只能为undefined(或不提供) | { [K in TextProp]?: undefined } & { [K in HandlerProp]?: undefined };
组合到组件Props中
type Props = { title: string; subtitle?: string; } & LinkedProps<'button1', 'handlerBtn1'> & LinkedProps<'button2', 'handlerBtn2'>;
验证效果
合法使用示例
// 两个按钮都有文本和处理器 const valid1: Props = { title: "Demo", button1: "按钮1", handlerBtn1: () => console.log("按钮1点击"), button2: "按钮2", handlerBtn2: () => console.log("按钮2点击") }; // 仅button1有文本和处理器,button2不提供 const valid2: Props = { title: "Demo", button1: "按钮1", handlerBtn1: () => console.log("按钮1点击") }; // 两个按钮都不提供 const valid3: Props = { title: "Demo" };
非法使用示例(TypeScript会报错)
// 错误:仅提供button1文本,缺少handlerBtn1 const invalid1: Props = { title: "Demo", button1: "按钮1" }; // 错误:仅提供handlerBtn1,缺少button1文本 const invalid2: Props = { title: "Demo", handlerBtn1: () => console.log("按钮1点击") };
内容的提问来源于stack exchange,提问作者noriktal
相关产品推荐
相关产品推荐

