DEV Community

Alireza Razinejad
Alireza Razinejad

Posted on

Some benefits of using class and interface together in Angular

Start with ECMAScript 2015 also known as ECMAScript 6, JavaScript has provided the ability to use this object-oriented class-base approach.

for full description read Classes in typescript.

simple class based example
class Passenger {
    private readonly _firstName: string;
    private readonly _lastName: string;

    constructor(fName: string, lName: string) {
        this._firstName = fName;
        this._lastName = lName;
    }

    get fullName(): string {
        return this._firstName + this._lastName;
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see classes can contain data members and member functions (fields and methods).

And with this class we can now create instance of our passenger every where we need to, like so.

let passenger= new Passenger('Anna', 'Brown');
Enter fullscreen mode Exit fullscreen mode

Now, let's say we want to make a contract inside our application to shape and force all classes to have some specific fields or maybe methods, maybe we need have them to be able to use that items inside some select component ! πŸ€·β€β™‚οΈ

Here's Interfaces can help us, as "One of TypeScript’s core principles is that type checking focuses on the shape that values have", you can read full description about Interfaces here.

Select able interface
interface SelectableElement {
    id: number;
    title: string;
}
Enter fullscreen mode Exit fullscreen mode

Now we have contract that can be implemented to our classes those we want to display their contents inside our select component πŸ‘

Let's implement SelectableElement to our Passenger class, and make it more usable inside our application 😎

class Passenger implements SelectableElement {
    id: number;
    private readonly _firstName: string;
    private readonly _lastName: string;

    constructor(fName: string, lName: string, id?: number) {
        this._firstName = fName;
        this._lastName = lName;
        this.id = id ?? Math.floor(Math.random() * 1000);
    }

    get fullName(): string {
        return this._firstName + this._lastName;
    }

    get title(): string {
        return this.fullName;
    }
}
Enter fullscreen mode Exit fullscreen mode

The most beautiful part is that immediately after implementing the our interface into the class, TypeScript will yell error and say we need to implement those members.

Another example will be when we will try to create Resolver inside our Angular application, as we need to implement Resolve or when we implementing LifeCycles to our components.

This was one of the benefits, the second one will be when we want to have contract when data is moving inside our application from service to service, or even when we want to send data to our Server Side Application or retrieving them from other web services !

One of practices that I truly ❀ is to have models inside our Front-End application independent of Back-End models ( or better to say Schema πŸ‘€ ), and then map them B4 sending to and after receiving them from our API ✌

Let's create Passenger interface
interface IPassenger {
    firstName: string;
    lastName: string;
}
Enter fullscreen mode Exit fullscreen mode

Can you see it ?? 🧐

Yes.. We can implement our interface to the class too !

class Passenger implements SelectableElement, IPassenger {
    id: number;
    firstName: string;
    lastName: string;

    constructor(fName: string, lName: string, id?: number) {
        this.firstName = fName;
        this.lastName = lName;
        this.id = id ?? Math.floor(Math.random() * 1000);
    }

    get fullName(): string {
        return this.firstName + this.lastName;
    }

    get title(): string {
        return this.fullName;
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see one of disadvantages will be that we can not have those two fields private any more, as we can not introduce private members to interfaces, maybe some day we can ! πŸ™„

Now let's see how we can implement some methods to our Passenger class to map data b4 send them to API πŸ₯±

But first for better read ability it can be good practice to introduce our API Schemas separately, like so

interface IPassengerSchema {
    identifier: number;
    lName: string;
    fName: string;
}
Enter fullscreen mode Exit fullscreen mode

Okay, now we are ready to implement methods for mapping passengers data 🎨

Map to Schema class Passenger
...
get mapToApiSchema(): IPassengerSchema {
    return {
        identifier: this.id,
        fName: this.firstName,
        lName: this.lastName
    }
}
...
Enter fullscreen mode Exit fullscreen mode

From now on we can use this method when ever we want to send passenger data to our Back-End, like so

const passenger = new Passenger('Anna', 'Brown');

const pDto = passenger.mapToApiSchema;

Enter fullscreen mode Exit fullscreen mode
Map from schema class Passenger
...
static getMapFromApiSchema(passenger: IPassengerSchema): IPassenger {
    return new Passenger(passenger.fName, passenger.lName, passenger.identifier);
}
...
Enter fullscreen mode Exit fullscreen mode

Now we can use this method like this

const passenger = Passenger.getMapFromApiSchema(passengerFromApi);
Enter fullscreen mode Exit fullscreen mode
Conclusion

Classes and Interface are both powerful and useful πŸ€”
Stop putting them versus each other and start using them together 🀐

Classes are rich objects that can contain everything that we expect from model ☺

Interfaces are contracts that will help us to keep our application data shape, the way we want 😏

Top comments (0)