如何在TypeScript中基于对象键保留类型信息并优化数据结构?
最佳TypeScript建模与React组件渲染方案
一、核心类型定义(解决TS7053类型索引错误)
首先明确各类型Item的结构,通过联合类型+映射类型构建类型安全的对象结构:
// 定义单个类型Item的复杂结构 type StrItem = { type: 'Str'; value: { content: string; maxLength: number; placeholder: string }; }; type NumItem = { type: 'Num'; value: { min: number; max: number; step: number; defaultValue: number }; }; // 新增类型只需扩展此联合类型 type Item = StrItem | NumItem; // 生成类型安全的Item对象映射:键为Item的type,值为对应类型的Item type ItemMap = { [K in Item['type']]: Extract<Item, { type: K }>; }; // 定义Section和SubSection结构 type SubSection = { items: ItemMap; // 其他子章节属性(如title、id等) }; type Section = { items: ItemMap; subSections: SubSection[]; // 其他章节属性 };
二、React组件映射与渲染
构建组件映射表,确保每个Item类型对应唯一组件,渲染时直接通过类型键匹配:
// 各类型Item的渲染组件 const StrItemComponent = ({ item }: { item: StrItem }) => { return ( <div className="str-item"> <input type="text" value={item.value.content} maxLength={item.value.maxLength} placeholder={item.value.placeholder} /> </div> ); }; const NumItemComponent = ({ item }: { item: NumItem }) => { return ( <div className="num-item"> <input type="number" min={item.value.min} max={item.value.max} step={item.value.step} defaultValue={item.value.defaultValue} /> </div> ); }; // 组件映射表:与Item类型一一绑定 const ItemComponentMap: Record<Item['type'], React.ComponentType<{ item: Item }>> = { Str: StrItemComponent, Num: NumItemComponent, }; // 章节渲染组件 const SectionRenderer = ({ section }: { section: Section }) => { return ( <div className="section"> {/* 渲染当前章节的Items */} <div className="section-items"> {Object.entries(section.items).map(([type, item]) => { const Component = ItemComponentMap[type as Item['type']]; return <Component key={type} item={item} />; })} </div> {/* 渲染子章节 */} {section.subSections.map((subSection, idx) => ( <div key={idx} className="sub-section"> {Object.entries(subSection.items).map(([type, item]) => { const Component = ItemComponentMap[type as Item['type']]; return <Component key={type} item={item} />; })} </div> ))} </div> ); };
三、方案优势
- 类型完全安全:通过
Extract工具类型和映射类型ItemMap,彻底解决TS7053索引类型错误,TypeScript能精确推断每个键对应的Item结构。 - 满足业务需求:对象结构确保每个类型的Item唯一,无需关心顺序,同时支持快速通过类型键访问对应数据。
- 高扩展性:新增Item类型时,只需三步:
- 新增对应
XXItem类型定义 - 扩展
Item联合类型 - 新增渲染组件并更新
ItemComponentMap
- 新增对应
- 代码可维护性:组件与类型一一绑定,避免分散判断逻辑,后期迭代更清晰。
可选优化:支持可选Item类型
如果部分类型的Item可能不存在,可将ItemMap改为部分映射:
type ItemMap = Partial<{ [K in Item['type']]: Extract<Item, { type: K }>; }>;
内容的提问来源于stack exchange,提问作者Evanss
相关产品推荐
相关产品推荐

