TypeScript React props实现to/onClick二选一约束报错解决
问题根因与修正方案
为什么会出现解构报错、约束失效
你遇到的问题本质是对TypeScript联合类型、交叉类型的规则存在两个认知偏差:
- 联合类型的属性访问限制:TypeScript定义的联合类型
A | B,代表变量的类型是「A的形状」或者「B的形状」,你只能直接访问A和B共同拥有的属性。如果直接访问仅存在于A或者仅存在于B的专属属性,TS就会抛出Property 'xxx' does not exist的错误。
对应到你的代码中:LinkWithOnclickProps没有定义to属性,LinkWithToProps没有定义onClick属性,两个类型的共有属性只有公共LinkProps中定义的内容,因此直接从联合类型propsType上解构to、onClick时,TS无法确定你当前拿到的是哪一种类型,自然会报错。 - 原定义未实现真正的二选一约束:你当前的类型写法实际允许用户同时传入
to和onClick两个属性——因为同时携带两个属性的对象,既符合LinkWithToProps的结构要求,也符合LinkWithOnclickProps的结构要求,可以顺利通过类型检查,完全达不到「必须二选一、不能同时传、不能都不传」的核心目标。
具体修正步骤
1. 定义严格互斥的props联合类型
给两个变体类型显式标记对方的专属属性never类型,从根源上禁止属性同时传入的情况:
type LinkProps = { children: any; // ...其余公共属性 }; // 携带to的变体:必须传入to,禁止传入onClick type LinkWithToProps = LinkProps & { to: string | { pathname: string }; onClick?: never; }; // 携带onClick的变体:必须传入onClick,禁止传入to type LinkWithOnclickProps = LinkProps & { onClick: (params: any) => void; to?: never; }; type propsType = LinkWithOnclickProps | LinkWithToProps;
修改后TS会自动拦截两类非法使用:
- 两个属性都不传入:两个变体都要求必须携带其中一个核心属性,缺失就会直接抛出类型错误
- 两个属性同时传入:每个变体都把对方的专属属性标记为
never,传入不符合要求的属性就会触发类型校验错误
2. 组件内部通过类型收窄安全访问专属属性
因为to和onClick是两个联合变体的专属属性,不能直接从外层联合类型上解构,需要通过分支判断把类型收窄到具体的变体后,再读取对应属性:
const InternalLink = (props: propsType) => { // 通过in操作符完成类型收窄 if ('to' in props) { // 进入该分支时,TS已经明确当前props是LinkWithToProps类型 const { to, children } = props; // 此处可直接使用to完成跳转逻辑 const href = typeof to === 'string' ? to : to.pathname; return <a href={href}>{children}</a> } // 走到此处时,剩余的唯一可能就是LinkWithOnclickProps类型 const { onClick, children } = props; // 此处可直接使用onClick完成点击逻辑 return <a onClick={onClick}>{children}</a> }
注意:如果直接在组件最外层写
const { to, onClick, children } = props,TS依然会抛出属性不存在的错误——此时还没有完成类型收窄,TS依然无法确定当前props对应的是哪一种变体,自然不允许直接访问非共有属性。
内容的提问来源于stack exchange,提问作者mughees ilyas
相关产品推荐
相关产品推荐

