TypeScript: Parameters with Interfaces

Eric Mok
7 min readFeb 6, 2019

--

Objective:

  • to provide a brief overview and quick start on implementing interfaces
  • to leave you understanding why interfaces can be useful in your projects

Reader Requirement:

  • Basic JavaScript
  • Little to no knowledge required of TypeScript.
  • Just know that TypeScript is a superset of JavaScript (meaning TypeScript is valid JavaScript but with additional methods and functionality)

Introduction

Ah yes, you’ve come across an interface in TypeScript. Maybe you’re using Angular or React, or maybe you want a piece of the small talk action the cool developers have (???). Whatever the reason, interfaces will probably come up and you’ll wonder three things:

  • What are Interfaces?
  • When do I use them?
  • How do I use them?

What Are Interfaces?

According to the official TypeScript documentation, type-checking “focuses on the shape that values have.” This really struck a chord with me. Whenever I recall anything about TypeScript, shape comes to mind first. Keep in mind, the whole point of TypeScript is to have structure and organization in your application code. Interfaces help provide that. When setting a type to functions, classes, or parameters, an interface is a useful way to define it.

Parameter with an Interface

A common use case for interfaces are in parameters. Many times you will have to pass a parameter, which is consistent across multiple functions. You might argue that can be done with a class but let’s save that for much later. For now, remember that interfaces are there to enforce a “contract”.

For this example, we’re creating an app that prepares ramen orders for a restaurant. Ramen dishes come in many varieties so we’ll need a structured, re-usable way to prepare these orders.

Let’s enforce the orders that a chef might receive in his kitchen.

Bowl of Ramen (https://unsplash.com/@migmal)

Simple Interface

First, we need a function that builds a ramen order for the chef.

Pass in a noodle as a string and a soup as a string. This is a way of doing it without an interface.

But wait! Every ramen order will consistently have multiple properties. Let’s just pass a set of properties as an object. Furthermore, at least two of these properties will be required (“noodle” and “soup”). In that case, we can implement an interface that enforces the parameters before the chef is given the order.

Using dish as an object will make it re-usable across similar functions and also save us code as the app scales
Every ramen order must have a noodle and a soup (even “soupless” counts)!

Now, when we make a call to the function makeRamen( ), we have to make sure the object that is passed contains the properties required by the RamenRecipe interface: noodle and soup. Any object that is passed into makeRamen( ) must at least have ‘noodle’ and ‘soup’. Notice here that the property types are also defined (‘noodle’ value as a string and ‘soup’ value as a string).

Chef will receive order to make ramen with noodle and soup

The dish being ordered in this example is basicRamen{ }. The chef will gladly take this order because the object passed into the parameter meets the requirements of the interface:

  1. Object contains the required properties
  2. Properties have the enforced type

Note: TypeScript only enforces the type-checking at compile time. For this reason, you may not see any type-checking errors at run time. You will see it in the editor or at compile time. We’ll re-iterate this point in the next sections.

There you have a function parameter implementing a simple interface. But what about something beyond basic ramen with additional ingredients?

Optional Parameters

To leave room for optional properties we can simply denote the interface properties with the “?” syntax.

I like pork belly, shiitake mushrooms, and a relative spicy level of 2 (on a scale of 0–5)

Not every ramen order will have a meat, vegetable, or spicy level. These properties will vary between customers. So, this interface will not only consider the potential preferences in each order, but will also leave room for the various values that will be passed to makeRamen( ). It helps the chef by limiting the possibility of errors from wrong order types (say, a fried rice recipe).

Here’s the whole picture.

Restricting Properties

But what if another developer not familiar with our ramen code, jumps into the middle of it. He needs to set up orders for a different chef who specializes in custom fried rice orders. He likes the simplicity of makeRamen( ) and decides to call the exact same function.

This actually runs fine. There won’t be any errors in the console. But we implemented an interface with specific properties required and optional where none include a “rice” property. Instead, you’ll receive a warning in the editor or at compile time.

This developer (with honest intentions) tried to re-use makeRamen( ), which is great but applied it in the wrong situation. Again, this runs fine. In fact, we could let this slide and leave it especially if makeRamen( ) was going to be this simple. But from a readability standpoint it would be awkward and confusing (make ramen …but make fried rice). Imagine this was an enterprise-scaled app and you had to pick up where a previous developer left off. Having warnings like this could prove useful.

Interfaces don’t actually restrict properties, instead it warns you of the potential for errors you could be accumulating. As long as the object parameter meets the required properties, anything can be added.

Immutability with Readonly properties

Another great feature of interfaces is the ability to set read-only types. Like the optional “?” syntax, we simply apply “readonly” to interface properties.

The properties “noodle” and “soup” can be set on a new variable.

But if you attempt to re-assign a property on basicRamen, TypeScript will throw an error in the editor or at compile time.

Like with the restricted properties in the previous section, this code will also run fine but will warn you. This is useful for creating objects that, for example, are depended on in different views but should not be modified — else causing an unintentional ripple effect across the application.

This is different from the keyword const. The official documentation says it best:

The easiest way to remember whether to use readonly or const is to ask whether you’re using it on a variable or a property. Variables use const whereas properties use readonly.

At this point, if you’re wondering how interfaces differ from classes, then you are correct to compare. They aren’t the same but it’s a common decision to make when building re-usable code. We’ll get to that later but for now, just know that interfaces don’t exist in the final, converted JavaScript bundle.

This is a relatively short breath when it comes to TypeScript. If you really want to go beyond my awesome food analogies, you can check out, “Angular Development with TypeScript” by Yakov Fain & Anton Moiseev. I had the pleasure of attending a few of Yakov’s talks. He really knows his TypeScript. Personally, it was on the higher end of my price range but that’s because it’s over 500 pages of in-depth knowledge. I picked at a lot of parts out of sequence. In fact, there are parts I never finished but can always go back to.

For information geared towards Angular, a very notable mention is “Angular 5: From Theory to Practice” by Asim Hussain. It was one of my first Angular reads. Whether you’re using Angular 5, 6 or 7 or even Angular 2 or 4, this book covers the foundational concepts of Angular. Syntax and dependencies may have updated since but I still return to this book whenever I need to brush up on essential Angular concepts. It’s definitely enough to get you started or to prepare you for more advanced concepts.

That concludes Parameters with Interfaces.

--

--