React判别式组件Props问题:未正确限制onSubmit传参
React组件判别式Props实现问题
需求说明
需要实现React组件的判别式Props规则:
- 仅当
multiSelect为true时,允许传入onSubmit,且禁止传入onSelect - 当
multiSelect显式为false或未提供时,禁止传入onSubmit,且必须传入onSelect
原代码问题
原实现中,未传入multiSelect时仍可传入onSubmit,不符合预期:
import React, { ReactNode } from 'react' type SelectionModalProps<T> = ( | { multiSelect: true onSubmit: (data: T[]) => void } | { multiSelect?: false onSelect: (nas: T) => void } ) & { data: T[] open: boolean title?: string onClose: () => void itemLabelGetter: (row: T) => ReactNode } const C = <T,>(props: SelectionModalProps<T>) => { return <></> } function Y() { return ( <C data={[{ name: 'something' }]} itemLabelGetter={() => <></>} onClose={() => {}} open title="some title" onSubmit={() => {}} // 💥 本应触发类型错误,但实际可正常传入 onSelect={() => {}} // multiSelect={true} /> ) }
问题原因
- 联合类型的第二个分支未明确禁止
onSubmit属性,TypeScript默认允许额外属性,不会触发报错 - 未传入
multiSelect时,TypeScript无法严格区分归属分支,导致不符合预期的属性被放行
解决方案
在两个分支中用never类型明确禁止对方的回调属性,严格区分单选/多选模式的Props约束:
import React, { ReactNode } from 'react' type SelectionModalProps<T> = ( | { multiSelect: true onSubmit: (data: T[]) => void onSelect?: never // 多选模式下禁止传入onSelect } | { multiSelect?: false onSelect: (nas: T) => void onSubmit?: never // 单选(含未指定)模式下禁止传入onSubmit } ) & { data: T[] open: boolean title?: string onClose: () => void itemLabelGetter: (row: T) => ReactNode } const C = <T,>(props: SelectionModalProps<T>) => { return <></> } // 测试用例:未传入multiSelect时传入onSubmit会触发类型错误 function Y() { return ( <C data={[{ name: 'something' }]} itemLabelGetter={() => <></>} onClose={() => {}} open title="some title" // onSubmit={() => {}} // ❌ 现在会触发类型错误 onSelect={() => {}} /> ) } // 测试用例:多选模式下传入onSelect会触发类型错误 function Z() { return ( <C data={[{ name: 'something' }]} itemLabelGetter={() => <></>} onClose={() => {}} open title="some title" multiSelect={true} onSubmit={() => {}} // onSelect={() => {}} // ❌ 现在会触发类型错误 /> ) }
效果说明
- 未传入
multiSelect或显式设为false时:必须传入onSelect,传入onSubmit会触发类型错误 - 显式设
multiSelect={true}时:必须传入onSubmit,传入onSelect会触发类型错误 - 公共属性(
data、open等)保持原有约束
内容的提问来源于stack exchange,提问作者Islam Y-
相关产品推荐
相关产品推荐

