Understanding TypeScript interfaces

June 24, 2018, 11:02 am Categories:

Categories

TypeScript (prior to ES6 at least) brought with it many improvements to the JavaScript language such as class based programming, abstract classes, strong data typing, string interpolation and interfaces (to name but a handful of new features).

In this tutorial we're going to take a look at interfaces and see how they can help improve our Ionic application development.

Understanding interfaces

An interface is a programming feature that helps to define the expected structure of an object allowing that to serve as a contract of sorts for the class where it is implemented.

That helps explain the concept but how does this actually translate into working with real world code?

Let's say for example we have the following method:

public requestSpecificArea(lat : number, lng : number) : Observable
{
  return this.http.get(this._api + `locate-neighbourhood?q=${lat},${lng}`);
}

As you can gather from the code we're using Angular's HttpClient class to query a remote API which returns data as an observable that we can subsequently subscribe to.

The data that is returned will be structured as follows:

{
  "description": [
    {
      "id":1,
      "region":"somewhere",
      "summary":"something"
    },
    {
      "id":2,
      "region":"somewhere else",
      "summary":"something else"
    }  
  ]
}

Should be fairly straightforward and any expected data will be returned right?

Not necessarily.

If Angular doesn't 'understand' the returned data then the HttpClient object will return back an error like the following:

Property 'description' does not exist on type Object

Pretty frustrating right?

This is where interfaces come to the rescue.

Defining your objects

In the previous example Angular's HttpClient class didn't understand the shape of the returned object hence the error that was published to the console.

Using interfaces we can define the expected structure of such an object (I.e. the keys and their expected data types) like so:

export interface IRegion {
   description: Array<IRegionDescription>;
}


export interface IRegionDescription {
   id: number;
   region: string;
   summary: string;
}

Here what we have done is very simple - created the following 2 interfaces (fyi: the generally accepted convention for naming interfaces is to prefix the name with a capitalised i):

  • IRegion
  • IRegionDescription

We begin with the IRegion interface which defines the expected data type for the description property within the returned data (which will be an Array type). Notice that we created a second interface named IRegionDescription to describe the structure of the data for that array? We then use this to help explain the structure for the property value within the IRegion interface.

By using interfaces we can describe the expected structure of our object be defining both their properties and their expected data types (I.e. string, number, boolean, array etc).

What if we encounter a situation where some of those properties might be present in some returned objects but not others?

In TypeScript these are referred to as optional properties and can be handled using the ? operator like so:

export interface IRegionDescription {
   id?: number;
   region?: string;
   summary?: string;
}

Putting it all together

Tyically I define my interfaces in separate files and store these within their own interfaces sub-directory within the Ionic applications' src directory. This allows me to separate my interfaces into one easily identifiable, central location making them easier to manage in the long run (it also keeps my code DRY - Don't Repeat Yourself - which I appreciate as a developer striving for good practice).

Alternatively you might prefer to store your interfaces within your TypeScript files above the class where they will be used.

Either approach is fine and I'll demonstrate both below.

Within my ionic-project/src/interfaces directory I create a TypeScript file named interface.region.ts which is structured as follows:

export interface IRegion {
   description: Array<IRegionDescription>;
}


export interface IRegionDescription {
   id: number;
   region: string;
   summary: string;
}

This is then imported into the class where it needs to be used with the following import statement:

import { IRegion } from '../../interfaces/interface.region';

We then implement this interface using type assertion to instruct Angular's HttpClient class on the expected data structure for the returned Observable:

public requestSpecificArea(lat : number, lng : number) : Observable
{
  return this.http.get<IRegion>(this._api + `locate-neighbourhood?q=${lat},${lng}`);
}

This then allows the data to be returned and parsed without throwing up any property not found errors.

If you prefer to define your interface within the class where it will be used simply do so as follows ABOVE the class definition like so:

export interface IRegion {
   description: Array<IRegionDescription>;
}


export interface IRegionDescription {
   id: number;
   region: string;
   summary: string;
}


@Injectable()
export class YourPageComponentClassOrProvider {

}

In summary

Interfaces are simply "contracts" used by classes to describe the expected shape (or structure) of data. These are particularly useful when you want your application to 'guarantee' the data is validly structured (and avoid those irritating property not found errors).

Whether you choose to define your interfaces within your components/services or store and organise those within their own dedicated interface files is entirely up to you. Neither approach is better nor worse than the other - it's entirely what works best for managing your project codebase/workflow.

If you've enjoyed what you've read and/or found this helpful please feel free to share your comments, thoughts and suggestions in the comments area below.

I explore different aspects of working with the Ionic framework in my e-book featured below and if you're interested in learning more about further articles and e-books that I'm writing please sign up to my FREE mailing list.

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top