【问题标题】:Getter Methods on Deserialized Objects in TypescriptTypescript 中反序列化对象的 Getter 方法
【发布时间】:2018-12-13 18:58:10
【问题描述】:

我们有各种对我们的服务的 Http 调用,它们返回一组对象。在我们的 Angular 应用程序中,如果指定,typescript 会将这些解释为适当的类型,例如 Person:

export class Person{
  public firstName: string;
  public lastName: string;
  public salutation: string;
}

假设我希望能够轻松地为这个用户构建一个问候字符串,但我想成为一个优秀的程序员并且只做一次而不是多次。所以我创建了一个 getter 来检索它:

export class Person{
  public firstName: string;
  public lastName: string;
  public salutation: string;
  public get greeting(): string {
      return salutation + " " + firstName + " " + lastName;
  }
}

然而,当 typescript 反序列化它时,它缺少了 greeting 属性的原型(它被设置为 undefined)。我知道打字稿正在将 JSON 对象映射到它拥有的类,并且映射对象上不存在任何丢失的字段/属性(如果调用则返回未定义)。解决此问题的最佳方法是什么?

作为我们如何调用服务的示例:

this.authHttp.post(this.url, user, params).then(
  (res: Person) => {
      console.log(res);
      console.log(res.greeting);
  }
);

【问题讨论】:

    标签: angular typescript angular5 angular-http


    【解决方案1】:

    您所做的工作巧合,因为您访问的属性名称也由来自.post 的响应提供。实际上,在将其转换为 JavaScript 源代码的 tsc 命令之后不再使用 TypeScript。因此,您会在运行时丢失所有类型检查。

    如果您要对该作业进行硬编码,如下所示:

    let me: Person = { firstName: 'Ian', lastName: 'MacDonald', salutation: 'Hello.' };
    

    您将在尝试创建 JavaScript 时收到 TypeScript 错误。

    Property 'greeting' is missing in type
        '{ firstName: string; lastName: string; salutation: string; }'
        but required in type 'Person'.ts(2741)
    

    您在类中定义的任何函数也会出现相同的错误。这是因为{ ... } 不是你的类型;它只有明确定义的内容。您的服务器响应所产生的结果将遵循相同的分配规则,但问题不会出现(因为数据不存在)直到运行时。

    我建议在任何尝试使用服务器响应之前使用管道为自己构造一个类的实例,以便在第一次联系时可以捕获任何错误,而不是 10 秒后当您最终尝试访问 .save() 操作时不存在。

    .post(...).pipe(map((incoming: any) => {
      let person: Person = new Person();
      person.firstName = incoming.firstName;
      person.lastName = incoming.lastName;
      person.salutation = incoming.salutation;
      return person;
    });
    

    【讨论】:

      【解决方案2】:

      你必须创建一个所谓的复制构造函数来接收对象的所有字段:

      constructor(firstName: string, lastName: string) {
          this.firstName = firstName;
          this.lastName = lastName;
      }
      

      现在你可以做

      http.post(...)
          .pipe(map(res => new Person(res.firstName, res.lastName)))
          .subscribe(...);
      

      当然,这有很多变体。你可以这样做

      constructor(public firstName: string, public lastName: string) {}
      

      例如,避免再次手动分配值。或者想想你想写这个的任何其他方式。归根结底都是一样的,即您需要实际创建类的instance,而不是仅将类类型用作类型。

      【讨论】:

        【解决方案3】:

        HTTP 调用的响应不会生成 Person 类的对象。响应实际上是一个纯 JavaScript 对象,显然没有 Person 类的 greeting() 方法。

        为了解决这个问题,您可以应用以下代码:

        http.post(...)
            .pipe(map(res => Object.assign(new Person(), res)))
            .subscribe(...);
        

        Object.assign(new Person(), res) 函数会将 res 的所有值复制到 Person 实例。在此映射之后,您将拥有一个真实的 Person 实例,其属性值从 http 调用返回的资源中复制。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-09-23
          • 2021-12-08
          • 1970-01-01
          • 2016-12-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多