TypeScript映射含enum属性的JSON为TS类型对象报错问题
问题原因
你遇到的类型错误来自两个写法问题:
- 函数入参类型声明错误:从API拉取的JSON解析后,
type字段是普通string类型,本身并不符合Seat类型要求的SEAT_TYPE枚举约束,你把convert的入参直接声明为Array<Seat>,传入原始解析数据时TS自然会报类型不匹配。 - 类型断言写法错误:
as keyof typeof SEAT_TYPE取的是枚举的键名联合类型,不是枚举本身的类型,在你的字符串枚举场景下虽然键名和值刚好重名,但属于歪打正着,换数字枚举或者值与键名不同的枚举就会出问题。
另外要注意:TS的类型断言只在编译阶段做类型检查欺骗,不会在运行时做任何类型转换,生产环境下不能完全信任后端返回值,最好加枚举合法性校验。
正确实现代码
首先定义接口返回的原始数据类型,和业务模型做区分:
// 接口返回的原始座位数据,type字段为普通字符串 type RawSeat = { number: string; type: string; status: boolean; }; export enum SEAT_TYPE { ECONOMY = "ECONOMY", PREMIUM_ECONOMY = "PREMIUM_ECONOMY", BUSINESS = "BUSINESS", } export type Seat = { number: string; type: SEAT_TYPE; status: boolean; }; export class SeatingPlan { seating: Seat[] = []; }
然后修正转换函数,加入可选的合法性校验:
export function convert(json: Array<RawSeat>): Seat[] { return json.map((seat) => { // 校验座位类型是否合法,避免后端返回脏数据 const isValidSeatType = Object.values(SEAT_TYPE).includes(seat.type as SEAT_TYPE); if (!isValidSeatType) { throw new Error(`解析座位数据失败,非法座位类型:${seat.type}`); } return { number: seat.number, type: seat.type as SEAT_TYPE, // 校验通过后再断言为枚举类型 status: seat.status, }; }); }
调用时先解析JSON再传入即可,不会再有类型错误:
// 解析接口返回的JSON字符串 const rawSeatData = JSON.parse(apiResponse) as RawSeat[]; // 转换为标准Seat类型数组 const seatList = convert(rawSeatData); // 填充到座位表实例 const seatingPlan = new SeatingPlan(); seatingPlan.seating = seatList;
简化写法(不推荐生产环境使用)
如果你可以100%确定后端返回的type值一定属于SEAT_TYPE枚举的合法值,可以跳过校验直接转换,代码更简洁:
export function convert(json: Array<Omit<Seat, 'type'> & {type: string}>): Seat[] { return json.map(seat => ({ ...seat, type: seat.type as SEAT_TYPE })); }
内容的提问来源于stack exchange,提问作者Nathan Leadill
相关产品推荐
相关产品推荐

