HTTP:从 JSON 对象到 Typescript 的类型断言
Posted
技术标签:
【中文标题】HTTP:从 JSON 对象到 Typescript 的类型断言【英文标题】:HTTP: Type assertion from JSON object to Typescript 【发布时间】:2016-10-14 00:52:11 【问题描述】:我正在阅读接口和类型断言。一直在看类似的页面:
Typescript parse json with class and interface How do I cast a json object to a typescript class(这个跟TS没关系!) Parse complex json objects with Typescript TS doc about interfaces我已经掌握了窍门,而且理解基础知识非常简单。虽然:当涉及 HTTP 时,我无法找到如何将 JSON 对象键入到我在应用程序中使用的对象。
例如,我有一个教师对象数组。每个教师都有一个 id、名字和一个学生数组。我有另一个班级学生,其中包含他们的属性......等等。
在我读到的那些链接的某个地方,除非您需要对对象执行操作,否则只有一个接口就足够了。但是除非您想对 Object 执行操作,否则您需要一个单独的类?
我实际的教师课程从...开始:
export class Teacher
private students: Array<Student>;
constructor(public id: string, public name: string)
this.students = new Array<Student>();
public getStudents(): Array<Student>
return this.students;
首先,如果我想将 JS 对象强制转换(或断言类型)为 Teacher 对象,代码会是什么样子?
现在我的代码看起来像这样:
服务:
getTeachers()
return this.http.get('someUrl')
.map((res: Response) => res.json())
组件(Angular 2 组件):
export class ListComponent implements OnActivate
id: string;
name: string;
teachers: Teacher[];
constructor(public _service: Service, public _router: Router)
routerOnActivate(): void
this._service.getTeachers()
.subscribe(teachers => this.teachers = teachers);
我的界面如下所示:
export interface TeacherJSON
id: string,
name: string,
students: Array<Student>;
如果上面的接口还不足以对对象执行动作,我该如何前进?我确实了解到您可以向界面添加方法,例如:
interface Thing
a: number;
b: string;
foo(s: string, n: number): string;
process(x: Thing)
return x.foo("abc");
我确实理解上面的例子,但我想 http、映射和订阅让我失望,我不知道如何在我的代码中实现它!
【问题讨论】:
【参考方案1】:那么显然我需要先将组件中的教师数组更改为我的界面实例?
没有接口实例这样的东西。接口是抽象的,它们只存在于 TypeScript 中,它们甚至不编译为 javascript。您编写它们是为了在您的编辑器中获得代码完成和其他好东西;在大型应用程序中为您提供帮助,因此您不必记住每个对象都有哪些属性和方法。
当您必须实例化一个对象时,接口不能这样做 - 您将使用一个类,并像往常一样创建属性和方法。在您的示例中执行此操作的正确方法是:
interface ITeacher
id: string,
name: string,
students: Array<Student>;
;
class Teacher implements ITeacher
id: string,
name: string,
students: Array<Student>;
在您的情况下,不需要实现接口,TypeScript 足够聪明,也可以从类中提取信息,所以它们是相同的:
teachers: Teacher[];
teachers: ITeacher[];
如果您有多种类型的教师,并且您想确保每个教师都具有所有必要的属性/方法,那么创建一个界面会很有意义:
class FirstGradeTeacher implements ITeacher
class SecondGradeTeacher implements ITeacher
您可能已经注意到我根本没有提到 JSON。 忘掉它! ...在使用您的对象模型(类或接口)时。它只是您的逻辑模型的数据格式。当您构建模型并计划它们应该如何工作时,您不需要关心协议和格式(Http 服务会处理这些)。
getTeachers(): Observable<Teacher>
return this.http.get('someUrl')
.map((res: Response) => res.json())
这段代码是你如何使用界面的。您只需告诉 TypeScipt,当您收到来自 someUrl
的响应并将其解析为 json
时,您希望数据是教师类型。
然后在其他地方当你subscribe()
到它时,它可以告诉你你得到的对象有id
、name
和students
属性:
this._service.getTeachers()
.subscribe((teachers: Teacher[]) => this.teachers = teachers);
希望这会有所帮助(:
【讨论】:
感谢您的回答。当然很难看出我的问题,因为你看不到完整的代码。我不能用我的界面扩展我的教师类,因为学生在课堂上是私人的。有人查看了我的代码,并被告知要实现一个接口来解决我的问题。我正在丢失数据,例如当我检索一位教师时。在那里,我必须将传入的老师映射为“新”老师,否则我会收到 self.context 错误。如果你看我的老师课,我只能说new Teacher(teacher.id, teacher.name)
。所以我已经在那里丢失了数据。
在我的服务中添加了 getTeacher
方法来展示我丢失数据的问题之一。
@Sasxa 为什么 res.json() 会转换为 Teacher?我正在寻找一些解释这一点的文档。
它没有转换它,它仍然只是一个 JSON。但是因为您希望响应将具有与教师相同的结构,所以您将其进行类型转换,并且您的工具和编辑器可以帮助您进行类型检查、自动完成、调试等...@TomDeseyn
@Sasxa 我没有找到演员表操作。 map 调用返回 Observable,它在哪里转换为 Observable如果我很好地理解了您的问题,您需要为以Object
作为原型的反序列化 JSON 对象提供一些方法。目前,纯 javascript API 无法做到这一点,因为您从 REST 服务接收到的内容是纯字符串,通过 JSON.parse
成为对象。您应该使用另一种反序列化机制,该机制能够在运行时检查您的类,并从反序列化的 JSON 重新构建它们的实例。通过这种方式,您将拥有新鲜的 JSON 对象,但具有正确的原型,该原型具有该类的所有方法。我试着举个例子。
假设您正在调用一个 REST 端点,该端点为您提供Teacher
-like 对象。在某些时候你会做var freshObject = JSON.parse(receivedString)
(实际上Angular已经做到了,但我们会改进这个机制);最简单的事情(但不是最明智的事情)是将freshObject
的原型更改为Teacher
原型:Object.setPrototypeof(freshObject, Teacher.prototype)
。现在您可以在freshObject
上调用Teacher
方法,但这显然是一个肤浅的变化,因为嵌套对象(在本例中为Student
s)仍然以Object
作为其原型,并且问题又来了。
现在很明显,我们需要能够递归研究Teacher
类结构的东西,同时使用正确的原型重新构建接收到的对象(实际上,您可以重新构建新的原型,而不是更改原型)副本,应该不那么重)。你可能想要这样的东西:Teacher.getClass().members
,它会给你这些信息:
students
字段的名称
students
字段的类型(在本例中为Array<Students>
)
组件类Student
的构造函数
如果您有此类信息,您可以递归地执行我们在上一个示例中所做的相同操作。
我最近发布了一个增强版的 TypeScript 编译器,它允许这个用例,我为你准备了一个完整的工作示例here,here 你可以找到编译器项目。如果这能解决您的问题,请告诉我。
【讨论】:
【参考方案3】:假设您通过 http 获取教师列表,您可以对其进行过滤以获取您需要的:
getById(id: string)
return this.http.get('someUrl' + id)
.map((res: Response) => res.json())
.filter(teacher => teacher.id === id));
【讨论】:
以上是关于HTTP:从 JSON 对象到 Typescript 的类型断言的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Angular2(Typescript)中的 Json 数组中获取值的总和