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

React+TypeScript:如何用映射而非条件判断收窄联合类型?

用组件映射实现带关联类型Props的React组件(无类型断言)

我需要实现一个React通用组件,它的data属性类型会随传入的type属性动态变化——data只能是Type1或Type2,且type会作为props的一部分传入。

最初的实现代码如下,但TypeScript会抛出类型错误:

interface BaseProps {
    className: string
}

interface Type1 { /* 此处定义Type1结构 */ }
interface Type2 { /* 此处定义Type2结构 */ }

type SomethingProps = ({type: "type1"; data: Type1} & BaseProps) | ({type: "type2"; data: Type2} & BaseProps)

function Something(props: SomethingProps) {
    const Component = componentMap[props.type];
    return <Component data={props.data} className={props.className} /> // TS错误:'Type1 | Type2'无法赋值给'Type1 & Type2'
}

const componentMap = {
    "type1": Type1Component, // FC<{data: Type1; className: string}>
    "type2": Type2Component // FC<{data: Type2; className: string}>
}

错误原因是TypeScript无法自动推断出props.type对应的组件和props.data的类型是匹配的,它会把data当成Type1 | Type2的联合类型,而组件期望的是各自专属的类型。

用if/else分支判断可以轻松解决这个问题,但我希望仅通过组件映射的方式实现,且不使用类型断言。


解决方案

核心思路是让组件映射的类型与Props的类型强关联,让TypeScript能准确跟踪type和data的对应关系:

import React from 'react';

interface BaseProps {
  className: string;
}

// 定义具体数据类型
interface Type1 {
  /* Type1的结构 */
}
interface Type2 {
  /* Type2的结构 */
}

// 定义组件映射的类型,明确每个type对应的组件参数类型
type ComponentMapType = {
  type1: React.FC<{ data: Type1 } & BaseProps>;
  type2: React.FC<{ data: Type2 } & BaseProps>;
};

// 实现组件映射
const componentMap: ComponentMapType = {
  type1: Type1Component,
  type2: Type2Component,
};

// 基于组件映射类型自动生成Props类型,确保type和data的关联
type SomethingProps = {
  [K in keyof ComponentMapType]: {
    type: K;
    data: Parameters<ComponentMapType[K]>[0]['data'];
  } & BaseProps;
}[keyof ComponentMapType];

// 使用泛型约束组件入参,让TS能准确推断类型
function Something<K extends keyof ComponentMapType>(props: Extract<SomethingProps, { type: K }>) {
  const Component = componentMap[props.type];
  return <Component data={props.data} className={props.className} />;
}

说明

  1. 强关联的类型定义:通过ComponentMapType明确每个type对应的组件及其参数类型,再基于这个类型生成SomethingProps,确保type和data的类型一一对应。
  2. 泛型约束:组件使用泛型K约束入参,TypeScript会根据传入的type自动推断出对应的data类型,无需额外断言。
  3. 无分支判断:完全通过组件映射实现渲染逻辑,保持代码简洁性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 05:30:52