typescript - ¿Cuándo usar Clase o Interfaz en un proyecto de Angular?
Estoy aquí hoy porque tengo una pregunta sobre, como dice el título, sobre clases e interfaces en Angular.
Desde mi punto de vista, entiendo esto:
Las interfaces se utilizan en Typescript para realizar la verificación de tipos, están presentes hasta la transpilación y desaparecen en producción. Además, una interfaz no puede ser utilizada para instanciar.
Las clases que vinieron con ES6 también se usan para la verificación de tipos, pero permanecen después de la transpilación y generan código en producción. Además, se usan para instanciar.
Entonces, básicamente, la interfaz es útil si no la necesitamos en producción, si solo necesitamos verificar tipos. Por el contrario, las clases están aquí si las necesitamos en producción, particularmente para la instanciación.
¿Estoy en lo correcto o me perdí algo sobre clases e interfaces?
Respuesta #1
Tienes razón. Las interfaces son geniales cuando solo necesitas la verificación de tipos, mientras que las clases son geniales cuando no solo quieres la verificación de tipos, sino que también necesitas algunos métodos o requieres otra lógica.
Personalmente, siempre empiezo usando solo una interfaz, y una vez que necesito algunos métodos, añado una clase y heredo la interfaz. También agregaría que prefiero siempre tener una interfaz, ya sea que estés usando una clase o no. Esto te permite pasar/inyectar la interfaz en lugar de tener que reinstanciar la clase múltiples veces.
Aquí hay un ejemplo de un patrón típico que seguiría si necesito algunos métodos (lo que significa que necesito una clase)
interface IPerson {
firstName: string;
lastName: string;
age: number;
getFullName(): string;
}
class Person implements IPerson {
public firstName: string;
public lastName: string;
public age: number;
constructor(firstName: string, lastName: string, age: number) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
getFullName(): string {
return `${this.firstName} ${this.lastName}`
}
}
const person: IPerson = new Person('John', 'Doe', 44);
Nunca inyectaría ni necesitaría importar Person en ningún lugar a menos que realmente necesitara 'crear' una nueva persona. Siempre puedo inyectar IPerson en su lugar y, mientras lo que se pasó como clase, la interfaz me permitirá llamar todos los métodos de la clase y acceder a las propiedades como desee.
Sin embargo, a veces no necesito métodos, sino un contrato de datos (o solo quiero evitar que TypeScript se enfade porque no le estoy diciendo qué es todo):
interface IPerson {
firstName: string;
lastName: string;
age: number;
}
const person: IPerson = <IPerson>{
firstName: 'John',
lastName: 'Doe',
age: 44
};
Hacerlo de esta manera todavía te da una forma de crear una variable al instante que se adhiera a la interfaz. Sin embargo, no hay métodos cuando lo haces de esta manera (así que pierdes tu función getFullName y tendrías que ejecutarla manualmente)
En general, me encuentro usando interfaces en los retornos HTTP que son JSON estructurado. Realmente no necesito hacer nada más con ellos en el front-end ya que el backend ya ha hecho el trabajo pesado por mí. Por lo tanto, crear una clase para cada uno de esos retornos puede ser excesivo, pero a algunas personas les gusta que sea así.
Otra cosa a mencionar es que crear todos estos modelos consume muchísimo tiempo. Sin embargo, vale la pena. En uno de mis proyectos, usé un módulo de npm para generar automáticamente interfaces de TypeScript a partir de mis modelos en C#. Eso ahorró mucho tipeo y me pareció bastante genial (https://www.npmjs.com/package/csharp-models-to-typescript)
Otra solución popular es usar Swagger Codegen. Puedes 'swaggerizar' tu backend y hacer que Swagger Codegen solo genere tus modelos y servicios para ti. Es bastante ingenioso. Aquí hay un repositorio de ejemplo que usa Angular y C# como backend.
En general, realmente es tu preferencia. Solo ten en cuenta que, si necesitas métodos y capas adicionales para desarrollar un modelo dado, lo mejor es una clase. Si solo necesitas tipos y no te importa el resto del 'azúcar sintáctico' elegante, solo usa una interfaz. Como mencionaste, las interfaces desaparecen en producción, así que ciertamente es una ventaja.
https://jsfiddle.net/mswilson4040/3vznkbq0/7/
Respuesta #2
Dado que también etiquetaste Angular en tu pregunta, quería agregar a la respuesta desde una perspectiva de Angular.
Angular también utiliza la Interfaz (o clase) como una estructura al recuperar datos vía http.
export interface Product {
id: number;
productName: string;
productCode: string;
tags?: string[];
price: number;
description: string;
imageUrl: string;
}
@Injectable({ providedIn: 'root' })
export class ProductService {
private productsUrl = 'api/products';
constructor(private http: HttpClient) { }
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>(this.productsUrl);
}
}
El método http.get obtiene los datos y llena la estructura de arreglo product proporcionada. Esto hace que sea mucho más fácil trabajar con los datos desde el componente.
