在React+TypeScript中指定RadioGroup仅接收Radio组件作为子元素
如何限定RadioGroup仅接收自定义Radio组件作为子元素
要实现RadioGroup只接受自定义Radio组件作为子元素,需要从编译时类型校验和运行时校验两方面入手,具体操作如下:
1. 编译时:通过TypeScript限定子元素类型
修改RadioGroupProps的children类型,把React.ReactNode替换为仅允许Radio组件的类型,同时修正RadioGroup的value和onChange类型(和Radio组件的value类型匹配,更符合单选组逻辑):
/* RadioGroup Component */ import { ReactElement } from 'react'; import { RadioProps } from './Radio'; // 导入Radio的Props类型 export interface RadioGroupProps { value?: string | number; onChange?: (value: string | number) => void; size?: "sm" | "lg" | "md"; radioStyle?: React.CSSProperties; // 限定children只能是单个或多个Radio组件元素 children: ReactElement<RadioProps> | ReactElement<RadioProps>[]; }
2. 运行时:校验子元素合法性
虽然TypeScript能在编译时限制,但仍需处理运行时可能出现的非法子元素(比如绕过类型检查传其他组件),可以在RadioGroup内部过滤或校验子元素,并同步Radio的状态:
export default function RadioGroup({ value, onChange, size = "md", radioStyle, children }: RadioGroupProps) { // 校验并过滤合法的Radio子元素,同时传递组内公共属性 const validRadioChildren = React.Children.map(children, child => { if (!React.isValidElement(child) || child.type.displayName !== 'Radio') { console.warn('RadioGroup的子元素只能是Radio组件'); return null; } // 给Radio传递选中状态、尺寸、样式及点击回调 return React.cloneElement(child, { size, radioStyle, checked: child.props.value === value, onChange: () => onChange?.(child.props.value) }); }); return ( <span className="radio-group-container"> {validRadioChildren} </span> ); }
同时给Radio组件补充属性并设置displayName,方便运行时识别:
/* Radio Child Component */ export interface RadioProps { value: string | number; label: string; size?: "sm" | "lg" | "md"; radioStyle?: React.CSSProperties; checked?: boolean; onChange?: () => void; } export function Radio({ value, label, size = "md", radioStyle, checked, onChange }: RadioProps) { return ( <span className={`radio-container radio-${size}`} style={radioStyle} onClick={onChange}> <span className={`radio ${checked ? 'radio-checked' : ''}`}></span> <span className="radio-label">{label}</span> </span> ); } // 设置displayName,用于RadioGroup的运行时校验 Radio.displayName = 'Radio';
最终使用方式
现在你可以像预期的那样使用组件,编译时传入非Radio组件会直接报错,运行时非法子元素会被过滤并给出警告:
<RadioGroup value="Sarah" onChange={(val) => console.log(val)}> <Radio label="Sarah" value={"Sarah"} /> <Radio label="Abraham" value={"Abraham"} /> </RadioGroup>
内容的提问来源于stack exchange,提问作者Oluwaferanmi Ajiboye
相关产品推荐
相关产品推荐

