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

React TypeScript组件:限制仅传入onAction或onDoubleAction其一Props

实现互斥的React Button回调属性

要实现onAction和onDoubleAction只能二选一的TypeScript约束,可以通过联合类型+never类型构造互斥属性类型,具体步骤如下:

1. 定义基础按钮属性

先提取按钮的公共属性,比如子元素、禁用状态等:

import React from 'react';

type BaseButtonProps = {
  children: React.ReactNode;
  disabled?: boolean;
  // 可添加其他公共属性,比如className、style等
};

2. 构造互斥的回调属性类型

创建两个分支类型,分别限制只能存在其中一个回调,同时将另一个回调设为never(表示该属性不允许被赋值):

type SingleActionProps =
  // 仅允许传入onAction,onDoubleAction必须为undefined或不传入
  | { onAction: (e: React.MouseEvent<HTMLButtonElement>) => void; onDoubleAction?: never }
  // 仅允许传入onDoubleAction,onAction必须为undefined或不传入
  | { onDoubleAction: (e: React.MouseEvent<HTMLButtonElement>) => void; onAction?: never };

3. 合并得到最终的ButtonProps

将基础属性和互斥回调属性交叉合并:

type ButtonProps = BaseButtonProps & SingleActionProps;

4. 实现Button组件

基于最终的类型定义编写组件:

const Button: React.FC<ButtonProps> = ({
  children,
  disabled = false,
  onAction,
  onDoubleAction
}) => {
  return (
    <button
      disabled={disabled}
      onClick={onAction}
      onDoubleClick={onDoubleAction}
      style={{ padding: '8px 16px', cursor: disabled ? 'not-allowed' : 'pointer' }}
    >
      {children}
    </button>
  );
};

5. 测试约束效果

  • 合法用法(仅传入单个回调):

    // 仅点击回调
    <Button onAction={(e) => console.log('点击事件', e)}>点击我</Button>
    
    // 仅双击回调
    <Button onDoubleAction={(e) => console.log('双击事件', e)}>双击我</Button>
    
    // 无回调(也允许)
    <Button>普通按钮</Button>
    
  • 非法用法(同时传入两个回调):

    // TypeScript会抛出错误:类型“(e: MouseEvent<HTMLButtonElement, MouseEvent>) => void”的参数不能赋给类型“undefined”的参数
    <Button 
      onAction={(e) => console.log('点击')} 
      onDoubleAction={(e) => console.log('双击')}
    >
      错误按钮
    </Button>
    

原理说明

通过never类型限制互斥属性的赋值,当同时传入两个回调时,TypeScript会检测到属性值与never类型冲突,从而抛出明确的错误提示,达到“二选一”的约束目的。

内容的提问来源于stack exchange,提问作者Husdady

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:50:27