我从远程REST服务器读取了一个JSON对象。这个JSON对象具有typescript类的所有属性(根据设计)。我如何转换收到的JSON对象的类型var?

我不想填充一个typescript变量(即有一个构造函数,以这个JSON对象)。它很大,在子对象和属性之间复制所有内容将花费大量时间。

更新:你可以将它转换为typescript接口!


当前回答

如果你正在使用ES6,试试这个:

class Client{
  name: string

  displayName(){
    console.log(this.name)
  }
}

service.getClientFromAPI().then(clientData => {
  
  // Here the client data from API only have the "name" field
  // If we want to use the Client class methods on this data object we need to:
  let clientWithType = Object.assign(new Client(), clientData)

  clientWithType.displayName()
})

但遗憾的是,这个方法对嵌套对象不起作用。

其他回答

我也遇到过类似的需求。 我想要一些能够让我轻松地从/转换到JSON的东西 这来自于对特定类定义的REST api调用。 我已经找到的解决方案是不够的,或者意味着重写我的 类的代码和添加注释或类似内容。

我想在Java中使用类似GSON的东西来序列化/反序列化类到JSON对象。

结合后来的需要,转换器也可以在JS中运行,我结束了编写自己的包。

它有一些开销。但启动后,添加和编辑非常方便。

初始化模块:

转换模式——允许在字段之间进行映射和确定 如何进行转换 类映射数组 转换函数映射-用于特殊转换。

然后在你的代码中,你像这样使用初始化的模块:

const convertedNewClassesArray : MyClass[] = this.converter.convert<MyClass>(jsonObjArray, 'MyClass');

const convertedNewClass : MyClass = this.converter.convertOneObject<MyClass>(jsonObj, 'MyClass');

或者,转换为JSON:

const jsonObject = this.converter.convertToJson(myClassInstance);

使用这个链接到npm包,以及如何使用模块:json-class-converter的详细说明

还包装了 Angular的用法: angular-json-class-converter

TLDR:一个班轮

// This assumes your constructor method will assign properties from the arg.
.map((instanceData: MyClass) => new MyClass(instanceData));

详细回答

我不推荐Object。赋值方法,因为它会不恰当地用类本身中没有声明的不相关属性(以及定义的闭包)丢弃类实例。

在您试图反序列化的类中,我将确保您想要反序列化的任何属性都已定义(null,空数组等)。通过用初始值定义属性,在尝试迭代要赋值的类成员时暴露了它们的可见性(请参阅下面的反序列化方法)。

export class Person {
  public name: string = null;
  public favoriteSites: string[] = [];

  private age: number = null;
  private id: number = null;
  private active: boolean;

  constructor(instanceData?: Person) {
    if (instanceData) {
      this.deserialize(instanceData);
    }
  }

  private deserialize(instanceData: Person) {
    // Note this.active will not be listed in keys since it's declared, but not defined
    const keys = Object.keys(this);

    for (const key of keys) {
      if (instanceData.hasOwnProperty(key)) {
        this[key] = instanceData[key];
      }
    }
  }
}

在上面的例子中,我简单地创建了一个反序列化方法。在实际示例中,我将它集中在可重用基类或服务方法中。

这里是如何利用这在一些像http响应…

this.http.get(ENDPOINT_URL)
  .map(res => res.json())
  .map((resp: Person) => new Person(resp) ) );

如果tslint/ide抱怨参数类型不兼容,只需使用尖括号<YourClassName>将参数转换为相同的类型,例如:

const person = new Person(<Person> { name: 'John', age: 35, id: 1 });

如果你有特定类型的类成员(又名:另一个类的实例),那么你可以通过getter/setter方法将它们强制转换为类型化实例。

export class Person {
  private _acct: UserAcct = null;
  private _tasks: Task[] = [];

  // ctor & deserialize methods...

  public get acct(): UserAcct {
    return this.acct;
  }
  public set acct(acctData: UserAcct) {
    this._acct = new UserAcct(acctData);
  }

  public get tasks(): Task[] {
    return this._tasks;
  }

  public set tasks(taskData: Task[]) {
    this._tasks = taskData.map(task => new Task(task));
  }
}

上面的例子将把acct和任务列表反序列化到它们各自的类实例中。

我发现了一篇关于将JSON转换为Typescript类的非常有趣的文章:

http://cloudmark.github.io/Json-Mapping/

你最终会得到如下代码:

let example = {
                "name": "Mark", 
                "surname": "Galea", 
                "age": 30, 
                "address": {
                  "first-line": "Some where", 
                  "second-line": "Over Here",
                  "city": "In This City"
                }
              };

MapUtils.deserialize(Person, example);  // custom class

假设json具有与typescript类相同的属性,你不需要将json属性复制到typescript对象中。你只需要在构造函数中传递json数据来构造Typescript对象。

在你的ajax回调中,你会收到一个company:

onReceiveCompany( jsonCompany : any ) 
{
   let newCompany = new Company( jsonCompany );

   // call the methods on your newCompany object ...
}

为了使它起作用:

1)在Typescript类中添加一个构造函数,将json数据作为参数。在该构造函数中,使用jQuery扩展json对象,如下所示:extend(this, jsonData)。美元。扩展允许保留javascript原型,同时添加json对象的属性。

2)注意你必须对链接对象做同样的事情。在本例中的Employees中,还创建了一个构造函数,用于接收Employees的json数据部分。你调用$。将json雇员转换为typescript雇员对象。

export class Company
{
    Employees : Employee[];

    constructor( jsonData: any )
    {
        $.extend( this, jsonData);

        if ( jsonData.Employees )
            this.Employees = $.map( jsonData.Employees , (emp) => {
                return new Employee ( emp );  });
    }
}

export class Employee
{
    name: string;
    salary: number;

    constructor( jsonData: any )
    {
        $.extend( this, jsonData);
    }
}

这是我在处理Typescript类和json对象时发现的最佳解决方案。

目前还没有自动检查从服务器接收到的JSON对象是否具有预期的(读取是否符合)typescript的接口属性。但是你可以使用用户定义的类型保护

考虑以下接口和一个愚蠢的json对象(它可以是任何类型):

interface MyInterface {
    key: string;
 }

const json: object = { "key": "value" }

三种可能的方法:

A.类型断言或放置在变量之后的简单静态强制转换

const myObject: MyInterface = json as MyInterface;

B.简单的静态铸造,前变量和菱形之间

const myObject: MyInterface = <MyInterface>json;

C.高级动态转换,你检查自己的对象结构

function isMyInterface(json: any): json is MyInterface {
    // silly condition to consider json as conform for MyInterface
    return typeof json.key === "string";
}

if (isMyInterface(json)) {
    console.log(json.key)
}
else {
        throw new Error(`Expected MyInterface, got '${json}'.`);
}

你可以玩一下这个例子

注意,这里的困难在于编写isMyInterface函数。我希望TS迟早会添加一个装饰器,将复杂的类型导出到运行时,并让运行时在需要时检查对象的结构。现在,您可以使用json模式验证器,其目的与此大致相同,也可以使用此运行时类型检查函数生成器