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

React根据Props渲染不同组件时的TypeError问题求助

解决React联合Props类型下的类型安全组件切换问题

问题根源

你的代码中,TypeScript无法通过brand和type的分支判断,自动将联合类型AllComps窄化为具体的子组件Props类型。这是因为TS无法追踪联合类型中brand与type的绑定关系——当你判断brand === 'one'时,TS只知道props是Comp1Props | Comp2Props,但无法在后续type === 'a'的判断中进一步确定它就是Comp1Props,因此会抛出类型不兼容的错误。

解决方案1:自定义类型守卫

通过手动编写类型守卫函数,明确告诉TS当前props属于哪个具体的Props类型,实现精确的类型窄化。

修改后的代码

import React from 'react';

interface Props<brand, type> {
    identification: {
        brand: brand,
        type: type
    };
    id: number;
}

type Comp1Props = Props<'one', 'a'>;
const Comp1: React.FC<Comp1Props> = props => <div>{JSON.stringify(props)}</div>;

type Comp2Props = Props<'one', 'b'>;
const Comp2: React.FC<Comp2Props> = props => <div>{JSON.stringify(props)}</div>;

type Comp3Props = Props<'two', 'b'>;
const Comp3: React.FC<Comp3Props> = props => <div>{JSON.stringify(props)}</div>;

type AllComps = Comp1Props | Comp2Props | Comp3Props;

// 自定义类型守卫函数
function isComp1Props(props: AllComps): props is Comp1Props {
  return props.identification.brand === 'one' && props.identification.type === 'a';
}

function isComp2Props(props: AllComps): props is Comp2Props {
  return props.identification.brand === 'one' && props.identification.type === 'b';
}

function isComp3Props(props: AllComps): props is Comp3Props {
  return props.identification.brand === 'two' && props.identification.type === 'b';
}

const Panel: React.FC<AllComps> = (props) => {
    if (isComp1Props(props)) {
        return <Comp1 {...props} />;
    }
    if (isComp2Props(props)) {
        return <Comp2 {...props} />;
    }
    if (isComp3Props(props)) {
        return <Comp3 {...props} />;
    }
    return <div />;
};

const Display: React.FC<AllComps> = (props) => (
    <Panel {...props} />
)

export default Display;

解决方案2:组件注册表(可扩展方案)

如果后续需要新增更多组件,用注册表的方式可以避免大量的if-else判断,同时保持类型安全。

修改后的代码

import React from 'react';

interface Props<brand, type> {
    identification: {
        brand: brand,
        type: type
    };
    id: number;
}

type Comp1Props = Props<'one', 'a'>;
const Comp1: React.FC<Comp1Props> = props => <div>{JSON.stringify(props)}</div>;

type Comp2Props = Props<'one', 'b'>;
const Comp2: React.FC<Comp2Props> = props => <div>{JSON.stringify(props)}</div>;

type Comp3Props = Props<'two', 'b'>;
const Comp3: React.FC<Comp3Props> = props => <div>{JSON.stringify(props)}</div>;

// 定义标识组合与Props的映射
type ComponentMap = {
  'one:a': Comp1Props;
  'one:b': Comp2Props;
  'two:b': Comp3Props;
};

// 生成所有Props的联合类型
type AllComps = ComponentMap[keyof ComponentMap];

// 组件注册表
const componentRegistry: {
  [K in keyof ComponentMap]: React.FC<ComponentMap[K]>;
} = {
  'one:a': Comp1,
  'one:b': Comp2,
  'two:b': Comp3,
};

const Panel: React.FC<AllComps> = (props) => {
  // 生成唯一标识key,断言为ComponentMap的键(安全,因为AllComps覆盖了所有组合)
  const key = `${props.identification.brand}:${props.identification.type}` as keyof ComponentMap;
  const Component = componentRegistry[key];
  return <Component {...props} />;
};

const Display: React.FC<AllComps> = (props) => (
    <Panel {...props} />
)

export default Display;

关键原理

两种方案都是通过明确类型关联关系让TypeScript正确识别分支中的具体类型:

  • 类型守卫函数通过返回值类型断言,直接告诉TS当前props的具体类型;
  • 组件注册表通过映射类型预先绑定标识组合与组件Props,避免了手动分支判断的类型模糊问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 20:05:30