HTTP: Aserción de tipo de objeto JSON a Typescript
He estado leyendo sobre interfaces y afirmación de tipos. He estado mirando páginas como:
- Typescript analizar JSON con clase e interfaz
- ¿Cómo convierto un objeto json a una clase de TypeScript (¡esto no tiene nada que ver con TS!)
- Analizar objetos json complejos con Typescript
- Documento TS sobre interfaces
Estoy empezando a entenderlo, y es bastante sencillo comprender los conceptos básicos. Aunque: en ninguna parte encuentro cómo escribir un objeto JSON a un objeto que uso en mi aplicación, cuando se trata de HTTP.
Por ejemplo, tengo un Array de objetos Teacher. Cada Teacher tiene un id, nombre y un Array de Students. Tengo otra clase Students que contiene sus atributos..... etc.
En algún lugar de esos enlaces leí que, a menos que necesites realizar acciones a un objeto, es suficiente con tener solo una Interfaz. ¿Pero a menos que quieras realizar acciones al Objeto necesitas una clase separada?
Mi clase actual de Profesor comienza con... :
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;
}
}
Primero que nada, ¿cómo se vería el código si quiero convertir (o afirmar el tipo) del objeto JS a un objeto Teacher?
Ahora mi código se ve algo así:
Servicio :
getTeachers() {
return this.http.get('someUrl')
.map((res: Response) => res.json())
}
Componente (Componente de 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);
}
Mi interfaz se vería así:
export interface TeacherJSON {
id: string,
name: string,
students: Array<Student>;
}
Si la interfaz anterior no es suficiente para poder realizar acciones sobre el objeto, ¿cómo avanzo? Aprendí que puedes agregar métodos a tu interfaz como:
interface Thing {
a: number;
b: string;
foo(s: string, n: number): string;
}
process(x: Thing) {
return x.foo("abc");
}
Entiendo el ejemplo anterior, pero supongo que el http, el mapeo y la suscripción me están confundiendo, ¡y no sé cómo implementarlo en mi código!
Respuesta #1
Entonces obviamente necesito primero cambiar mi arreglo de profesores en el componente a una instancia de mi interfaz?
No existe tal cosa como una instancia de la interfaz. Las interfaces son abstractas, existen solo en TypeScript, ni siquiera se compilan a JavaScript. Las escribes para obtener autocompletado y otras ventajas en tu editor; para ayudarte en aplicaciones grandes, de modo que no tengas que recordar qué propiedades y métodos tiene cada objeto.
Cuando tienes que instanciar un objeto, las interfaces no pueden hacer eso; usarás una clase y crearás propiedades y métodos como de costumbre. La manera correcta de hacer esto en tu ejemplo sería:
interface ITeacher{
id: string,
name: string,
students: Array<Student>;
};
class Teacher implements ITeacher {
id: string,
name: string,
students: Array<Student>;
}
En tu caso, implementar una interfaz no es necesario, TypeScript es lo suficientemente inteligente como para extraer la información de las clases también, por lo que estos serían iguales:
teachers: Teacher[];
teachers: ITeacher[];
Crear una interfaz tendría sentido si tienes varios tipos de profesores y quisieras asegurarte de que cada uno tenga todas las propiedades/métodos necesarios:
class FirstGradeTeacher implements ITeacher{}
class SecondGradeTeacher implements ITeacher{}
Es posible que hayas notado que no he mencionado JSON en absoluto. ¡Olvídalo! ...cuando trabajas con tus modelos de objetos (clases o interfaces). Es solo un formato de datos para tus modelos lógicos. Cuando estás estructurando tus modelos y planeando cómo deberían funcionar, no te importa sobre protocolos y formatos (el servicio HTTP se encarga de eso).
getTeachers(): Observable<Teacher> {
return this.http.get('someUrl')
.map((res: Response) => res.json())
}
Este código es cómo utilizarías una interfaz. Simplemente le dices a TypeScript que cuando recibas una respuesta de someUrl y la analices como json, esperas que los datos sean del tipo Teacher.
Luego, en otros lugares, cuando te subscribe() a él, puede decirte que el objeto que estás recibiendo tiene las propiedades id, name y students:
this._service.getTeachers()
.subscribe((teachers: Teacher[]) => this.teachers = teachers);
Espero que esto ayude (:
Respuesta #2
Suponiendo que estás obteniendo la lista de profesores vía HTTP, puedes filtrarla para obtener el que necesitas:
getById(id: string) {
return this.http.get('someUrl' + id)
.map((res: Response) => res.json())
.filter(teacher => teacher.id === id));
