根据构造函数名称将JSON /对象转换为自定义对象

时间:2018-07-18 12:39:22

标签: javascript angular typescript constructor casting

我尝试通过给定的字符串创建/投射对象。

我已经可以通过给定的原型来投射对象。但是我需要将内部对象强制转换为它们的类,以使用特定的属性。

我的第一种方法是使用接口并使用它扩展/继承我的模型。当我执行“静态转换方法”时,当前的原型未定义。

//IBaseModel.ts

class IBaseModel {
    constructorClass: string;
  
    constructor() {
        this.constructorClass = this.constructor.name;
    }
  
    static fromJSON(json: any){
        if(typeof json === 'string') {
            //use second parameter "reviver" for JSON.parse, definition see below.
            return JSON.parse(json, InterfaceBaseModel.reviver)
        } else {
            let obj = eval(`new ${json.constructorClass}()`), //eval "new Test()"
                retval = Object.assign(obj, json); //assign each property
           
            for(let prop in retval) {
                //every property that contains the property constructorClass should be casted as well.
                if(retval[prop].constructorClass)
                    retval[prop] = InterfaceBaseModel.fromJSON(retval[prop]);
            }
    
            return retval;
        }
    }
  
    static reviver(key: string, value: any): any {
        //every property that contains the property constructorClass should be casted as well.
        return value.constructorClass ? InterfaceBaseModel.fromJSON(value) : value;
    }
}

//Test.ts
import IBaseModel from 'path';
import SubTest from 'path';

class Test extends IBaseModel {
  text: string;
  subTest: SubTest;

  constructor(text: string, subTest: SubTest) {
    super();
    this.text = text;
    this.subTest = subTest;
  }
}

//SubTest.ts
import IBaseModel from 'path';

class SubTest extends IBaseModel {
  value: number;

  constructor(value: number) {
    super();
    this.value = value;
  }
}

//test.service.ts
import Test from 'path';

export class TestService {

  constructor() { }
  
  setLocalData(key: string, value: any) {
    localStorage.setItem(key, value);
  }

  getLocalData(key: string){
    let localData = localStorage.getItem(key),
        retval;
    
    if(localData)
      retval = Test.fromJSON(localData);
    //ERROR in "IBaseModel.ts": Test is not defined.
    //Importing the class is NO option! 
    //As we want to use it for many classes!
    return retval;
  }
}

如上所述,由于未定义当前类和子类,因此我在BaseModel内部遇到错误。

我的下一个方法是为给定的“类类型”编写一个转换函数。

//castObject.ts
export function castObject<T>(json: any, type: IConstructor<T>){
  if(typeof json === 'string')
    return JSON.parse(json, reviver)
  else {
    let obj = this.activator(type),
        retval = Object.assign(obj, json);
    //until here it works like a charm!

    for(let prop in retval) {
        if(retval[prop].constructorClass)
            retval[prop] = castObject<T>(retval[prop], type); 
            //the type for sub-classes is not given...
            //SubTest is casted to Test
    }

    return retval;
  }
}

function reviver(key: string, value: any): any {
  return value.constructorClass ? castObject(value) : value;
}

function activator<T>(type: IConstructor<T>): T {
  //create a new instance of the given type.
  return new type();
}

interface IConstructor<T> {
  //a typeless constructor, to surpass every class-type
  new (...args: any[]): T;
}

//test.service.ts
import { castObject } from 'path'
...
  getLocalData(key: string){
    ...
    retval = castObject<Test>(localData, Test);
    //sub-classes are getting the wrong type.
  }

我的最后一种方法是使用字符串强制转换对象。像这样:

for(let prop in retval) {
    if(retval[prop].constructorClass)
        retval[prop] = retval[prop] as retval[prop].constructorClass;
}

我没有发现任何有关基于字符串(构造函数名称)强制转换对象的信息。

也许您可以帮助我或引导我解决正确的问题。

0 个答案:

没有答案