【问题标题】:TypeScript: Recursively creating complex objectsTypeScript:递归创建复杂对象
【发布时间】:2017-09-08 11:40:44
【问题描述】:

使用 Angular 和 TypeScript,我们可以使用泛型和所有编译优点来确保某种类型的安全性。但是如果我们使用例如 HTTP 服务,我们不会得到一个特定的对象,而只是解析 JSON。例如,我们有一些通用方法可以做到这一点:

public get<T>(relativeUrl: string): Promise<T> {
    const completeUrlPromise = this.createCompleteUrl(relativeUrl);
    const requestOptions = this.createRequestOptions(ContentType.ApplicationJson, true);
    return completeUrlPromise.then(completeUrl => {
      return this.processResponse<T>(this.http.get(completeUrl, requestOptions));
    });
  }

  private processResponse<T>(response: Observable<Response>): Promise<T> {
    const mappedResult = response.map(this.extractData);

    const result = mappedResult.toPromise();
    return result;
  }

  private extractData(res: Response): any {
    let body;
    if (!Array.isArray(res)) {
      if (res.text()) {
        body = res.json();
      }
    } else {
      body = res;
    }

    if (!JsObjUtilities.isNullOrUndefined(body)) {
      return body;
    }

    return {};
  }

最终,泛型类型在这种情况下是无用的,因为我们只是得到 JSON。如果通用对象具有 JSON 中没有的方法或属性,它们就会丢失。 为了避免这种情况,我们添加了传递构造函数来真正创建对象的可能性:

 private processResponse<T>(response: Observable<Response>, ctor: IParameterlessConstructor<T> | null = null): Promise<T> {
    let mappedResult = response.map(this.extractData);

    if (ctor) {
      mappedResult = mappedResult.map(f => {
        const newObj = JsObjFactory.create(f, ctor);
        return newObj;
      });
    }

    const result = mappedResult.toPromise();
    return result;
  }

JsObjFactory 看起来像这样:

export class JsObjFactory {
  public static create<T>(source: any, ctorFn: IParameterlessConstructor<T>): T {
    const result = new ctorFn();
    this.mapDefinedProperties(source, result);

    return result;
  }

  private static mapDefinedProperties<T>(source: Object, target: T): void {
    const properties = Object.getOwnPropertyNames(target);

    properties.forEach(propKey => {
      if (source.hasOwnProperty(propKey)) {
        target[propKey] = source[propKey];
      }
    });
  }
}

这适用于浅层对象,但如果属性也是具有构造函数的复杂类型,则不起作用。由于运行时没有类型,我目前最好的办法是解析属性,检查类是否存在,然后创建它们。但这似乎非常容易出错和繁琐。

由于我一直很确定,我不是唯一遇到此问题的人,是否有解决方案或我不知道的 TypeScript/JavaScript 功能,这会有所帮助?

【问题讨论】:

标签: javascript json typescript generics


【解决方案1】:

我个人不会这样做,但它可能是您正在寻找的。​​p>

例子:

Customer.ts

export interface ICustomer {
    Id: number;
    Name: string;
    Orders: IOrder[];
    ...
}

export class Customer implements ICustomer {
    public Id: number;
    public Name: string;
    public Orders: IOrder[];

    constructor(customer: Partial<ICustomer>) {
        this.Id = customer.Id || 0;
        this.Name = customer.Name || '';
        this.Orders = [];
        customer.Orders.forEach((order: IOrder) => this.Orders.push(new Order(order)));
    }

    //some functions
}

Order.ts

export interface IOrder {
    Id: number;
    Weight: number;
    Shipmentdate: string;
}

export class Order implements IOrder {
    public Id: number;
    public Weight: number;
    public Shipmentdate: string;

    constructor(order: Partial<IOrder>) {
        this.Id = order.Id || 0;
        this.Weight = order.Weight || 0;
        this.Shipmentdate = order.Shipmentdate || '';
    }

    //some functions
}

这将使Object(在本例中为Customer)负责实例化您传入的已知复杂类型。而Order 反过来可以拥有它实例化的复杂类型。

【讨论】:

  • 谢谢,试一试。问题是,除了名称之外,我如何仅从 JSON 中知道要创建什么?
  • @MatthiasMüller 类自己知道吗?还是我误会了你?
猜你喜欢
  • 2015-05-03
  • 1970-01-01
  • 2017-12-07
  • 1970-01-01
  • 1970-01-01
  • 2019-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多