如何用JSON导入属性修改类实例并保留原类类型?
TypeScript 自定义类对象序列化/反序列化问题解决
我是编程新手,若该问题已有解答还请见谅——我没能找到合适的解决方案!
我定义了一个creature类,其中部分属性是其他自定义类的实例:
export class creature { pos: vector2; target: vector2; path: Array<vector2>; length: number; maxDist: number; weights: number; id: string; mainArrayId: number; segments: Array<creatureJoint>; head: creatureHead; legs: Array<creatureJoint>; interactingId: string; state: string; traits: { [key: string] : number }; health: number; energy: number; }
我的保存/加载流程是:先对对象执行JSON.stringify()保存,加载时用JSON.parse()解析,再创建creature新实例,最后用解析后的JSON属性填充实例。加载函数如下:
export function replaceCurrentState(loadedState : { [key : string]: creature }) : void { creatures = []; deadCreatures = []; creaturesReference = {}; Object.keys(loadedState).forEach(function(i) { new creature(new vector2(0,0),16,4,2,i); let baseCreature : creature = creaturesReference[i]; let loadCreature : creature = loadedState[i]; for (let [key, value] of Object.keys(baseCreature)) { } }); }
现在遇到两个问题:
- JSON无法识别自定义类,解析后
vector2这类属性会变成普通对象,而非原类实例。 - 尝试遍历属性赋值时,出现“cannot assign to type never”错误。
解决思路
JSON只能序列化基本类型和普通对象,无法保存类的原型信息,必须手动处理自定义类的实例还原,同时修正遍历赋值的类型问题。
1. 给自定义类添加实例还原方法
以vector2为例,添加静态方法用于从JSON对象创建类实例,可选添加自定义序列化逻辑确保保存的数据简洁:
export class vector2 { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } // 静态方法:从JSON对象还原vector2实例 static fromJSON(obj: {x: number, y: number}): vector2 { return new vector2(obj.x, obj.y); } // 可选:自定义序列化逻辑,只保存必要属性 toJSON() { return {x: this.x, y: this.y}; } }
同理给creatureJoint、creatureHead添加相同逻辑的fromJSON方法。
2. 修改加载函数,针对性处理属性赋值
放弃盲目遍历,手动区分基本类型和自定义类型属性,确保类型匹配:
export function replaceCurrentState(loadedState : { [key : string]: any }) : void { creatures = []; deadCreatures = []; creaturesReference = {}; Object.values(loadedState).forEach(loadData => { // 创建新的creature实例 const newCreature = new creature( vector2.fromJSON(loadData.pos), loadData.length, loadData.maxDist, loadData.weights, loadData.id ); // 赋值基本类型属性 newCreature.mainArrayId = loadData.mainArrayId; newCreature.interactingId = loadData.interactingId; newCreature.state = loadData.state; newCreature.traits = {...loadData.traits}; newCreature.health = loadData.health; newCreature.energy = loadData.energy; // 还原自定义类实例/数组 newCreature.target = vector2.fromJSON(loadData.target); newCreature.path = loadData.path.map(vec => vector2.fromJSON(vec)); newCreature.segments = loadData.segments.map(joint => creatureJoint.fromJSON(joint)); newCreature.head = creatureHead.fromJSON(loadData.head); newCreature.legs = loadData.legs.map(joint => creatureJoint.fromJSON(joint)); // 将实例加入全局集合 creatures.push(newCreature); creaturesReference[newCreature.id] = newCreature; }); }
3. 若坚持遍历赋值,修正类型错误
如果想通过遍历实现,需要添加类型断言并判断属性类型,避免类型不匹配:
Object.entries(baseCreature).forEach(([key, _]) => { // 断言key为creature的合法属性名 const propKey = key as keyof creature; const loadValue = loadCreature[propKey]; // 根据属性类型进行实例还原 if (propKey === 'pos' || propKey === 'target') { baseCreature[propKey] = vector2.fromJSON(loadValue); } else if (propKey === 'path') { baseCreature[propKey] = loadValue.map(vec => vector2.fromJSON(vec)); } else if (propKey === 'segments' || propKey === 'legs') { baseCreature[propKey] = loadValue.map(joint => creatureJoint.fromJSON(joint)); } else if (propKey === 'head') { baseCreature[propKey] = creatureHead.fromJSON(loadValue); } else { // 基本类型直接赋值 baseCreature[propKey] = loadValue; } });
内容的提问来源于stack exchange,提问作者Jensen Grundy
相关产品推荐
相关产品推荐

