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

如何基于字符串字面量类型定义TypeScript条件类型适配Redux Store?

解决TypeScript条件类型匹配Redux Store与React组件类型问题

没问题,我来帮你实现这个需求——让ILabelingStore的frames类型根据labelingType自动绑定,同时让React组件无需反复类型检查就能直接处理对应类型的数据。

第一步:定义类型映射表

先创建一个类型映射关系,把ILabelingTypes的每个取值对应到它专属的frames类型,后续可以通过索引直接获取对应类型:

type ILabelingTypes = "pedestrians" | "vehicles";
interface IFrame { url: string; orientation: number }

// 建立labelingType与frames类型的映射
type LabelingFramesMap = {
  pedestrians: Map<string, IFrame[]>;
  vehicles: IFrame[];
};

第二步:创建泛型版ILabelingStore接口

用泛型来绑定labelingType和frames的类型关联,这样当指定labelingType时,frames的类型会被TypeScript自动推导:

interface ILabelingStore<T extends ILabelingTypes> {
  labelingType: T;
  frames: LabelingFramesMap[T];
}

现在你声明不同类型的store时,frames类型会自动匹配:

// 类型校验通过:frames自动为Map<string, IFrame[]>
const pedestrianStore: ILabelingStore<"pedestrians"> = {
  labelingType: "pedestrians",
  frames: new Map([["group1", [{ url: "/frame1.jpg", orientation: 0 }]]])
};

// 类型校验通过:frames自动为IFrame[]
const vehicleStore: ILabelingStore<"vehicles"> = {
  labelingType: "vehicles",
  frames: [{ url: "/car-frame.jpg", orientation: 90 }]
};

第三步:Redux状态类型定义

如果你的Redux状态需要兼容两种store类型,可以用联合类型来表示:

type LabelingStoreState = ILabelingStore<"pedestrians"> | ILabelingStore<"vehicles">;

第四步:React组件无需类型检查直接使用

针对不同类型的store,我们可以创建接收特定泛型props的组件,组件内部的frames类型会被自动推断,完全不用手动校验:

Pedestrians专属组件

import React from "react";

type PedestriansProps = {
  store: ILabelingStore<"pedestrians">;
};

class PedestriansComponent extends React.Component<PedestriansProps> {
  queue: IFrame[] = [];

  componentDidMount() {
    // frames自动识别为Map<string, IFrame[]>,直接用Object.entries遍历
    Object.entries(this.props.store.frames).forEach(([key, val]) => {
      this.queue = this.queue.concat(val);
    });
  }

  render() {
    return <div>行人标注组件</div>;
  }
}

Vehicles专属组件

type VehiclesProps = {
  store: ILabelingStore<"vehicles">;
};

class VehiclesComponent extends React.Component<VehiclesProps> {
  queue: IFrame[] = [];

  componentDidMount() {
    // frames自动识别为IFrame[],直接concat即可
    this.queue = this.queue.concat(this.props.store.frames);
  }

  render() {
    return <div>车辆标注组件</div>;
  }
}

可选:同一组件兼容两种类型(用类型守卫)

如果需要在单个组件里处理两种store类型,可以写类型守卫函数来缩小类型范围,避免手动类型断言:

// 类型守卫函数,帮助TypeScript识别store类型
function isPedestriansStore(store: LabelingStoreState): store is ILabelingStore<"pedestrians"> {
  return store.labelingType === "pedestrians";
}

function isVehiclesStore(store: LabelingStoreState): store is ILabelingStore<"vehicles"> {
  return store.labelingType === "vehicles";
}

// 通用标注组件示例
type GenericLabelingProps = {
  store: LabelingStoreState;
};

class GenericLabelingComponent extends React.Component<GenericLabelingProps> {
  queue: IFrame[] = [];

  componentDidMount() {
    if (isPedestriansStore(this.props.store)) {
      // 此处frames自动为Map<string, IFrame[]>
      Object.entries(this.props.store.frames).forEach(([key, val]) => {
        this.queue = this.queue.concat(val);
      });
    } else if (isVehiclesStore(this.props.store)) {
      // 此处frames自动为IFrame[]
      this.queue = this.queue.concat(this.props.store.frames);
    }
  }

  render() {
    return <div>通用标注组件</div>;
  }
}

这样实现后,TypeScript会全程帮你做类型校验,再也不用在组件里反复写类型检查或者手动断言啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:02:07