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

如何让TypeScript根据枚举动态推导回调的对象类型?

TypeScript动态推导回调参数类型问题解决

问题场景

给定以下TypeScript代码:

enum stores {
  book,
  chapter,
  verse
}

const reducer = {
  [stores.book]: { a: 'string', b: 1 },
  [stores.chapter]: { a: 'string', c: 2 },
  [stores.verse]: { a: 'string', d: false }
}

function main ({
  storeName,
  getA
}:{
  storeName: stores,
  getA: (item: typeof reducer[stores]) => void
}) {
  const item = reducer[storeName]
  getA(item)
  return
}

main({storeName: stores.verse, getA(item) {
  item.a // 仅能访问公共属性a,但
  item.d // 无法访问stores.verse特有的属性d
}})

当前getA回调仅能识别item的公共属性a,无法根据传入的storeName动态识别对应对象的特有属性。需要让TypeScript根据storeName和reducer动态推导getA中item的准确类型,该场景用于React-Redux通用组件开发,需在props函数中获取Redux切片对象的精确类型。

解决方案

核心思路是用泛型绑定storeName与getA参数的类型关联,让TypeScript根据传入的storeName自动推导对应切片的精确类型。

优化后的基础代码

enum stores {
  book,
  chapter,
  verse
}

const reducer = {
  [stores.book]: { a: 'string', b: 1 },
  [stores.chapter]: { a: 'string', c: 2 },
  [stores.verse]: { a: 'string', d: false }
}

// 给main函数添加泛型S,约束为stores枚举的成员
function main<S extends stores>({
  storeName,
  getA
}: {
  storeName: S,
  // 让getA的参数类型对应reducer中S对应的具体类型
  getA: (item: typeof reducer[S]) => void
}) {
  const item = reducer[storeName]
  getA(item)
  return
}

main({
  storeName: stores.verse,
  getA(item) {
    item.a // 正常访问公共属性
    item.d // 现在可正确识别并访问stores.verse特有的属性d
  }
})

main({
  storeName: stores.book,
  getA(item) {
    item.b // 可访问book特有的属性b
  }
})

原理说明

  1. 泛型S约束为stores枚举成员,确保storeName只能传入枚举内的有效值;
  2. 将getA的参数类型指定为typeof reducer[S],TypeScript会根据storeName对应的泛型S,自动关联reducer中对应键的具体类型,实现动态推导;
  3. 调用main时,传入不同storeName,TypeScript会自动推导出getA参数的精确类型,支持访问对应切片的特有属性。

React-Redux场景适配

在React-Redux通用组件中,可将泛型逻辑应用到组件Props定义:

import { useSelector } from 'react-redux';

// 定义根状态类型,包含所有切片
type RootState = {
  [stores.book]: typeof reducer[stores.book],
  [stores.chapter]: typeof reducer[stores.chapter],
  [stores.verse]: typeof reducer[stores.verse]
};

// 泛型组件Props
type GenericComponentProps<S extends stores> = {
  storeName: S;
  onSliceData: (data: RootState[S]) => void;
};

function GenericComponent<S extends stores>({ storeName, onSliceData }: GenericComponentProps<S>) {
  const sliceData = useSelector((state: RootState) => state[storeName]);
  
  const handleTrigger = () => {
    onSliceData(sliceData);
  };

  return <button onClick={handleTrigger}>获取切片数据</button>;
}

// 使用组件时自动推导类型
<GenericComponent 
  storeName={stores.chapter} 
  onSliceData={(data) => {
    console.log(data.c); // 正确识别chapter特有的属性c
  }} 
/>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 22:35:16