I’m here today because I’ve a question about, like the title said, about classes and interfaces in Angular.
From my Point of View, I understand this:
Interfaces are used in Typescript to perform type-checking, they are here until the transpilation and disappear in the production. Also Interface cannot be used to instantiate.
Classes came from ES6 are also used for type-checking, but they stay after transpilation and generate code in the production. Also, they are used to instantiate.
So, basically, Interface is useful if we don’t need them in production, if we only need to type-check.
On the opposite, Class are here if we need them in production, particularly for the instantiation.
I am Correct or Did I miss something about class and interface?
You're correct. Interfaces are great when you only need the type checking whereas classes are great when you not only want the type checking, but you need some methods or require some other logic.
Personally, I always start with just using an interface, and once I need some methods, I'll add a class to it. I would also add that I personally prefer to always have an interface whether you're using a class or not. This allows you to pass around/inject the interface instead of having to re-instantiate class multiple times.
Here is an example of a typical pattern I would follow if I need some methods (which means I need a class
)
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);
I would never inject or need to import Person
anywhere unless I actually needed to 'new up' a new person. I can always inject IPerson
instead and so long as what was passed in as the class, the interface will allow me call all the class methods and access the properties as I wish.
However, sometimes I don't need methods, but I need a data contract (or just want to suppress TypeScript from being pissed off I'm not telling it what everything is:
interface IPerson {
firstName: string;
lastName: string;
age: number;
}
const person: IPerson = <IPerson>{
firstName: 'John',
lastName: 'Doe',
age: 44
};
Doing it this way still gives you a way to create a variable on the fly that adheres to the interface. However, there's not methods when you do it this way (so you lose your getFullName
function and would have to run that manually`
Overall, I find myself using interfaces on http returns that are structured json. I don't really need to do anything more to them on the front as the backend has done the heavy lifting for me already. So, creating a class for each one of those returns may be overkill, but some people prefer it that way.
One other thing to bring up is that creating all these models is extremely time consuming. It pays off though. In one of my projects, I used an npm module to automatically generate TypeScript interfaces based off my c# models. That saved a ton of typing and thought it was pretty cool (https://www.npmjs.com/package/csharp-models-to-typescript)
In general, it's really your preference. Just keep in mind, if you need methods and extra layers to build out a given model, a class is best. If you just need types and don't care about the rest of the fancy 'syntactical sugar' just use an interface. As you mentioned, interfaces disappear in production so it's certainly a plus.
https://jsfiddle.net/mswilson4040/3vznkbq0/7/
Since you also tagged Angular in your question, I wanted to add to the answer from an Angular perspective.
Angular also uses the Interface (or class) as a structure when retrieving data via 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);
}
}
The http.get
method gets the data and populates the provided product
array structure. This makes it much easier to work with the data from the component.