Interfaces
Now we come to one of the key pillars of Object oriented programming, using interfaces
to represent behavior. Programming to interfaces enables us to abstract out the behavior that we would like our classes to encode. This is often referred as "programming to the interface instead of "programming to the implementation".
This style of programming gives us two benefits:
- If we program to interfaces we can change the implementation easily.
- The interface represents a contract. We can use this contract to enable the compiler to check that they types we implement conform to this contract.
- Interfaces can also be used as constraints on Generic types. (We will cover this in the section on Generics)
Let us look at the interface that represents a Person. Here the interface requires that the person have two properties (fullName
, id
)
//defining contracts with interfaces
//interfaces are structural
interface IPerson {
fullName: string;
id: number;
}
Using interfaces with functions:
You can use interfaces to constrain the parameters of a function.
//A function that uses the interface IPerson
function displayPerson(person: IPerson) {
display(`id: ${person.id} Name : ${person.fullName}`);
}
displayPerson({fullName:"Jim Brown", id:10});
Notice that typeScript uses structural typing, so the value passed as a parameter of the function displayPerson
does not have to derive from IPerson, it just have the have the same structure.
This allows us to design our function interfaces as structured types, rather than a long list of parameters.
Typescript interfaces support optional parameters and methods so we can also define an interface like this:
interface IPerson {
fullName: string;
id: number;
//optional properties
age?: number;
toString(): string;
}
Interfaces and classes
classes and explicitly implement the interface using the implement
keyword as follows:
class Person implements IPerson {
fullName: string;
static instanceCounter = 0;
constructor(public id: number, public firstName, public lastName) {
this.fullName = this.firstName + " " + this.lastName;
Person.instanceCounter += 1;
}
greeting(): string {
return `Hello from an instance of Person, my name is ${this.fullName}`;
}
}
displayPerson(new Person(2, "John", "Smith"));
Although as we said before the call to displayPerson would work without explicitly implementing the interface.