You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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}
    />
  )
}

问题原因

  1. 联合类型的第二个分支未明确禁止onSubmit属性,TypeScript默认允许额外属性,不会触发报错
  2. 未传入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-

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:56:29