Getter Typescript 中反序列化对象的方法

Getter Methods on Deserialized Objects in Typescript

我们有各种 Http 调用我们的服务,return 对象的集合。在我们的 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 反序列化它时,它缺少问候语 属性 的原型(它被设置为未定义)。我知道打字稿正在将 JSON 对象映射到它拥有的 class,并且映射对象上不存在任何缺失的 fields/properties(returning undefined 如果被调用)。解决此问题的最佳方法是什么?

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

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

您必须创建所谓的复制构造函数,它接收对象的所有字段:

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) {}

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

您的工作巧合,因为您访问的 属性 名称也由 .post 的响应提供。实际上,在 tsc 命令将其转换为 JavaScript 源后不再使用 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)

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

我建议在任何尝试使用服务器响应之前使用管道为自己构造一个 class 的实例,这样任何错误都可以在第一次联系时被捕获,而不是 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;
});

HTTP调用的响应不生成Person的对象class。响应实际上是一个普通的 JavaScript 对象,显然没有 Person class.

的 greeting() 方法

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

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

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