我们对返回对象集合的服务进行了各种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属性的原型(它被设置为未定义(。我发现typescript正在将JSON对象映射到它所拥有的类,并且映射的对象上不存在任何丢失的字段/属性(如果调用,则返回undefined(。解决这个问题的最佳方法是什么?
作为我们如何调用服务的示例:
this.authHttp.post(this.url, user, params).then(
(res: Person) => {
console.log(res);
console.log(res.greeting);
}
);
您所做的工作纯属巧合,因为.post
的响应也提供了您正在访问的属性名称。事实上,TypeScript在tsc
命令之后不再使用,该命令将TypeScript转换为JavaScript源代码。因此,在运行时将丢失所有类型检查。
如果你要硬编码这个任务,就像这样:
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;
});
您必须创建一个所谓的复制构造函数,它接受对象的所有字段:
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) {}
以避免再次手动分配值。或者想想你想用什么其他方式写这篇文章。归根结底,您需要实际创建类的实例,而不是仅将类类型用作类型。
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调用返回的资源中复制的。