HTTP:从JSON对象到Typescript键入断言

时间:2016-06-13 14:35:48

标签: json http typescript angular

我已经阅读了界面并输入了断言。一直在看这样的页面:

我掌握了它,并且理解基础知识非常简单。虽然:当涉及到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())
}

组件(角度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,映射和订阅让我失望,而且我不知道如何在我的代码中实现它!

3 个答案:

答案 0 :(得分:2)

  

所以显然我需要先将组件中的teacher数组更改为我的界面实例?

没有接口的实例。接口是抽象的,它们只存在于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()的其他地方,它可以告诉你,你所获得的对象有idnamestudents属性:

this._service.getTeachers()
  .subscribe((teachers: Teacher[]) => this.teachers = teachers);

希望这会有所帮助(:

答案 1 :(得分:1)

假设您通过http获取教师列表,您可以对其进行过滤以获得所需的教师:

fn tick(&mut self) {
    for d in &mut self.ods {
        let mut should_nullify = false;
        if let Some(ref mut du) = *d {
            du.capacity -= 1;
            if du.capacity == 0 {
                should_nullify = true;
            }
        }
        if should_nullify {
            *d = None;
        }
    }
}

答案 2 :(得分:1)

如果我理解你的问题,你需要为反序列化的JSON对象提供一些方法,该对象以Object为原型。目前,使用普通的javascript API是不可能的,因为从REST服务收到的内容是一个普通的字符串,它通过JSON.parse成为一个对象。您应该使用另一个反序列化机制,该机制能够在运行时检查您的类,并从反序列化的JSON重新构建它们的实例。通过这种方式,您将获得新的JSON对象,但使用具有该类所有方法的正确原型。我会试着举个例子。

假设您正在调用一个REST端点,它为您提供Teacher个对象。在某些时候你做var freshObject = JSON.parse(receivedString)(实际上Angular已经做到了,但我们将改进这种机制);最简单的做法(但不是最明智的做法)是将freshObject的原型更改为Teacher原型:Object.setPrototypeof(freshObject, Teacher.prototype)。现在你可以Teacher上调用freshObject方法,但这显然是一个浅薄的变化,因为嵌套对象(在这种情况下为Student)仍然有{{ 1}}作为他们的原型,问题又出现了。

现在很明显,我们需要一些能够在使用正确的原型重新构建接收到的对象的同时调查Object类结构递归的东西(实际上,相反,您可以更改原型)建立新鲜的副本,应该减少重量)。您可能需要以下内容:Teacher,它们会为您提供以下信息:

  • Teacher.getClass().members字段的名称
  • students字段的类型(本例中为students
  • 组件类Array<Students>
  • 的构造函数

如果您有此类信息,您可以递归执行我们在上一个示例中所做的相同操作。

我最近发布了一个允许这个用例的TypeScript编译器的增强版本,我为你准备了一个完整的工作示例here,并且here你可以找到编译器项目。如果这可以解决您的问题,请告诉我。