如何在TypeScript中动态访问对象映射键并获取对应值?
我有如下数据结构:
data: { returned: { items: { payment_returned: { count: randFloat(), percentage: randFloat() } }, meta: { count: 1000, percentage: 1000 } }, rejected: { items: { external_validation_failed: { count: randFloat(), percentage: randFloat() }, missing_capability: { count: randFloat(), percentage: randFloat() }, payment_request_cancelled: { count: randFloat(), percentage: randFloat() }, validation_schema_failed: { count: randFloat(), percentage: randFloat() }, conversion_to_v1_failed: { count: randFloat(), percentage: randFloat() } }, meta: { count: 1000, percentage: 1000 } }, // ...其他类似结构的键 }
该结构在data对象的多个键下重复。我需要同时获取data的键(如returned、rejected这类类别),以及对应类别下meta.count的值。目前已成功拿到类别列表,但动态获取对应meta.count时遇到TypeScript报错。
我的实现代码:
const WidgetCategories = () => { const { data, isLoading, isSuccess } = useGetStatisticsDataQuery(); const [categories, setCategories] = useState<PayoutState[]>(); useEffect(() => { if (data) { const categoriesArray = Object.keys(data.data); setCategories(categoriesArray as unknown as PayoutState[]); } }, [isSuccess, data]); return ( <> <div className="w-68 cursor-pointer rounded-lg bg-white p-4 shadow-plain-lg"> <p className="mb-8 text-sm font-bold">Payouts states</p> {isSuccess && categories ? categories.map((category: PayoutState) => { console.log(data.category); return ( <Link className="align-center mb-2 ml-4 flex cursor-pointer text-sm font-medium" to="/payouts/:category" key={category} > <PayoutBadge type={category} count={9} /> </Link> ); }) : null} </> ); };
当前问题:映射categories时使用data.category触发TypeScript错误:Property 'category' does not exist on type 'StatisticsResponse',但category确实是StatisticsResponse中data的合法键。同时需要确保count值与对应类别正确关联并传递给组件。
对应的类型定义:
export interface StatisticsResponse { data: { returned: ItemsData; rejected: ItemsData; completed: ItemsData; action_required: ItemsData; pending: ItemsData; processing: ItemsData; received: ItemsData; }; }
1. 正确动态取值
TypeScript报错是因为.操作符只能访问类型上明确声明的属性,动态键需要使用方括号语法。将data.category改为data.data[category]即可获取对应类别的数据,再提取meta.count:
const categoryData = data.data[category]; const count = categoryData.meta.count;
2. 强化类型安全
为让TypeScript识别category是data的合法键,先定义一个类型来获取StatisticsResponse['data']的键:
type PayoutState = keyof StatisticsResponse['data'];
这样就无需as unknown as PayoutState[]这种强制类型转换,直接将Object.keys(data.data)转为PayoutState[]更安全:
const categoriesArray = Object.keys(data.data) as PayoutState[];
3. 简化组件逻辑
无需用useState存储categories,直接在渲染阶段处理即可,减少不必要的状态更新:
const WidgetCategories = () => { const { data, isLoading, isSuccess } = useGetStatisticsDataQuery(); if (isLoading) return <div>加载中...</div>; if (!isSuccess || !data) return null; const categories = Object.keys(data.data) as PayoutState[]; return ( <div className="w-68 cursor-pointer rounded-lg bg-white p-4 shadow-plain-lg"> <p className="mb-8 text-sm font-bold">Payouts states</p> {categories.map((category) => { const count = data.data[category].meta.count; return ( <Link className="align-center mb-2 ml-4 flex cursor-pointer text-sm font-medium" to={`/payouts/${category}`} key={category} > <PayoutBadge type={category} count={count} /> </Link> ); })} </div> ); };
4. 修复路由参数问题
原代码中to="/payouts/:category"是硬编码的占位符,需用模板字符串替换为实际的category值:to={/payouts/${category}},确保跳转后路由显示正确。
内容的提问来源于stack exchange,提问作者user19625670

