TypeScript与Fetch结合优化:React中复用Pokemon数据转换逻辑
抽离Pokemon表单数据转API格式的重复逻辑
当然可以用Object.keys().reduce把转换逻辑抽离到独立文件里,彻底消除创建和更新操作的代码重复。下面是具体实现步骤:
1. 抽离转换逻辑到工具函数
新建一个工具文件(比如src/utils/apiTransform.ts),把abilities转IRI数组的逻辑封装成通用函数:
// src/utils/apiTransform.ts import type { PokemonFormData, ApiPokemon } from '../types'; export const transformPokemonForApi = (formData: PokemonFormData): ApiPokemon => { return Object.keys(formData).reduce((apiData, key) => { const fieldKey = key as keyof PokemonFormData; // 处理关联字段:将abilities转换为API所需的IRI数组 if (fieldKey === 'abilities') { apiData.abilities = formData[fieldKey].map(ability => `/api/abilities/${ability.id}`); } else { // 普通字段直接映射 apiData[fieldKey as keyof ApiPokemon] = formData[fieldKey] as any; } return apiData; }, {} as ApiPokemon); };
2. 定义对应的TypeScript类型
在src/types/index.ts里明确表单数据和API数据的类型,保证类型安全:
// src/types/index.ts // 前端表单收集的数据结构 export interface PokemonFormData { name: string; abilities: Array<{ id: number; name: string }>; // 其他字段(比如身高、体重等)按需添加 } // API平台接受的数据结构 export interface ApiPokemon { name: string; abilities: string[]; // 存储技能的IRI字符串数组 // 其他字段和表单对应 }
3. 在创建/更新函数中复用工具函数
现在创建和更新Pokemon的代码可以简化成:
// 创建Pokemon const createPokemon = async (formData: PokemonFormData) => { const apiData = transformPokemonForApi(formData); const res = await fetch('/api/pokemons', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(apiData), }); if (!res.ok) throw new Error('创建Pokemon失败'); return res.json(); }; // 更新Pokemon const updatePokemon = async (pokemonId: number, formData: PokemonFormData) => { const apiData = transformPokemonForApi(formData); const res = await fetch(`/api/pokemons/${pokemonId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(apiData), }); if (!res.ok) throw new Error('更新Pokemon失败'); return res.json(); };
扩展说明
如果以后需要处理其他关联字段(比如Pokemon的属性types),只需要在transformPokemonForApi的reduce逻辑里加一个判断分支即可,完全不用修改创建/更新的业务代码,扩展性很强。
内容的提问来源于stack exchange,提问作者Christophe Bogaert
相关产品推荐
相关产品推荐

