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

React PropTypes结合defaultProps与InferProps的类型兼容问题

解决React 17.0.2中propTypes、defaultProps与InferProps的类型冲突问题

问题场景

以下是出现类型错误的代码示例:

Container.tsx

import PropTypes from 'prop-types';
import { InferProps } from 'prop-types';

const InfoPropType = {
  legend: PropTypes.string.isRequired,
  value: PropTypes.number,
};

const ContainerPropTypes = {
  config: PropTypes.shape({
    c1: PropTypes.shape(InfoPropType).isRequired,
  }),
};

type ContainerType = InferProps<typeof ContainerPropTypes>;

const ContainerDefaultProps = { config: { c1: { value: 1 } } };

const Container = (props: ContainerType & typeof ContainerDefaultProps): JSX.Element => {
  const { config: cConfig } = props;

  return (
    <div>
      {cConfig.c1.legend} has {cConfig.c1.value}
    </div>
  );
};

Container.propTypes = ContainerPropTypes;
Container.defaultProps = ContainerDefaultProps;

App.tsx

import Container from './Container';

type ConfigType = { c1: { legend: string; value?: number; } };

const App = (): JSX.Element => {
  const aConfig: ConfigType = { c1: { legend: 'l1' } };

  return (<Container config={aConfig} />); // 此处出现类型错误
};

export default App;

错误信息

类型“ConfigType”无法赋值给类型“InferPropsInner<Pick<{ c1: Validator<NonNullable<InferProps<{ legend: Validator<string>; value: Requireable<number>; }>>>; }, "c1">> & Partial<...> & { ...; }”。
  类型“ConfigType”无法赋值给类型“{ c1: { value: number; }; }”。
    两者的“c1.value”类型不兼容。
      类型“number | undefined”无法赋值给类型“number”。
        类型“undefined”无法赋值给类型“number”。

预期类型来自属性“config”,该属性在类型“IntrinsicAttributes & Pick<Pick<InferPropsInner<Pick<{ config: Requireable<InferProps<{ c1: Validator<NonNullable<InferProps<{ legend: Validator<string>; value: Requireable<number>; }>>>; }>>>; }, never>> & Partial<...> & { ...; }, "config"> & Pick<...> & Pick<...>, never> & Partial<...> & Partial<...>'上声明

错误核心是:传入的aConfig中value为可选字段,但组件props类型却要求value为必填,导致类型不匹配。


解决方案

1. 修正组件Props类型定义

错误根源是将ContainerType与typeof ContainerDefaultProps交叉作为props类型,强制要求外部传入value字段。只需去掉这个交叉,仅使用InferProps推断的类型即可:

// Container.tsx 修改后
const Container = (props: ContainerType): JSX.Element => {
  const { config: cConfig } = props;
  // 利用Nullish合并运算符处理可能的undefined,同时依赖defaultProps兜底
  return (
    <div>
      {cConfig.c1.legend} has {cConfig.c1.value ?? ContainerDefaultProps.config.c1.value}
    </div>
  );
};

2. 优化组件内部类型安全(可选)

如果希望TypeScript直接识别到cConfig.c1.value不会是undefined,可以手动合并类型,同时在组件内部合并props与defaultProps:

// Container.tsx 优化版
type ContainerProps = Partial<typeof ContainerDefaultProps> & ContainerType;

const Container = (props: ContainerProps): JSX.Element => {
  // 合并传入的props与默认值,确保内部使用的是完整配置
  const mergedConfig = { ...ContainerDefaultProps.config, ...props.config };
  return (
    <div>
      {mergedConfig.c1.legend} has {mergedConfig.c1.value}
    </div>
  );
};

3. 验证结果

修改后,App.tsx中的ConfigType与组件config属性的类型完全匹配,类型错误会自动消失。


原理说明

  • InferProps会根据propTypes正确推断出value为可选类型(number | undefined)。
  • defaultProps的作用是在组件内部为可选属性提供默认值,不需要通过类型交叉强制外部传入该属性。
  • 错误的类型交叉会覆盖InferProps的正确推断,导致可选属性被标记为必填。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:55:54