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

React TypeScript中如何合并同一组件的多种Props类型?

问题:如何在不暴露核心组件类型的前提下合并组件Props?

假设我有<SomeComponent />组件:

interface IProps {
  label: string;
}

export const SomeComponent = (props: IProps) => {
  return /* 组件内容 */
}

另外有一个处理拖拽(drag and drop)功能的DnDProvider组件,它接受DropTarget参数:

interface IDropSourceProps {
  isDropped: boolean;
  /* 其他Props */
}

interface IDnDProviderProps {
  DropTarget: React.ElementType<IDropSourceProps>;
}

export const DnDProvider = ({ DropTarget }: IDnDProviderProps) => {
  const isDropped = /* 拖拽状态逻辑 */;
  return <DropTarget isDropped={isDropped} />
}

当我把SomeComponent传入DnDProvider时:

<DnDProvider DropTarget={SomeComponent} />

TypeScript抛出错误:

Types of parameters 'props' and 'props' are incompatible.
Type 'IDropSourceProps' has no properties in common with type 'IProps'.

我想要合并两种Props类型(一种属于业务组件本身,另一种由DnDProvider传入)。由于DnDProvider是核心组件,我希望将其类型与业务组件分离,但目前无法获取DropTarget的Props类型。

当前的解决方案是让业务组件的Props扩展核心组件的类型:

interface IProps extends IDropSourceProps {
  label?: string;
}

但我不想把核心组件的类型暴露给上层业务组件,请问还有其他解决方案吗?


解决方案:使用泛型实现类型隔离与自动合并

通过给DnDProvider添加泛型参数,可实现核心拖拽类型与业务组件类型的完全隔离,同时自动合并两种Props,无需业务组件显式扩展核心类型。

修改后的DnDProvider实现

import React from 'react';

// 核心拖拽Props,仅在核心模块内部使用,不对外暴露
interface IDropSourceCoreProps {
  isDropped: boolean;
  /* 其他核心拖拽相关Props */
}

// 定义带泛型的DnDProvider Props
interface IDnDProviderProps<TComponentProps = {}> {
  // 要求传入的组件能接收「业务Props + 核心拖拽Props」的合并类型
  DropTarget: React.ElementType<TComponentProps & IDropSourceCoreProps>;
  // 传递业务组件自身的Props(自动排除核心拖拽Props,避免冲突)
  componentProps?: Omit<TComponentProps, keyof IDropSourceCoreProps>;
}

// 实现泛型版本的DnDProvider
export const DnDProvider = <TComponentProps extends {}>({
  DropTarget,
  componentProps = {} as TComponentProps
}: IDnDProviderProps<TComponentProps>) => {
  const isDropped = /* 拖拽状态逻辑,比如从Context或内部state获取 */;
  
  // 合并核心拖拽Props与业务组件Props
  const mergedProps = {
    ...componentProps,
    isDropped
  } as TComponentProps & IDropSourceCoreProps;

  return <DropTarget {...mergedProps} />;
};

业务组件保持独立

业务组件无需依赖任何核心拖拽类型,完全保持原有定义:

interface IProps {
  label: string;
}

export const SomeComponent = (props: IProps) => {
  return <div>{props.label}</div>;
};

使用方式

TypeScript会自动推导业务组件的Props类型,无需额外配置:

<DnDProvider 
  DropTarget={SomeComponent} 
  componentProps={{ label: "测试拖拽组件" }} 
/>

核心原理

  • 泛型TComponentProps自动捕获业务组件的Props类型,通过TComponentProps & IDropSourceCoreProps约束传入的组件能兼容合并后的Props。
  • Omit<TComponentProps, keyof IDropSourceCoreProps>确保componentProps仅包含业务组件自身的属性,避免与核心拖拽Props冲突。
  • 核心拖拽类型IDropSourceCoreProps完全封装在核心模块内部,业务层无法感知,实现了类型隔离的目标。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 11:40:37