Overview of advanced types in TypeScript

Advanced types in TypeScript



16.11.2020

Introduction to advanced types

In the last post, I told you about the benefits of using TypeScript and basic TypeScript types. Now is the time for more advanced types & tricks in TS. Let’s get started.

Interface

Okay, so what is an Interface? In basic words, an Interface is like an object with a type. Makes sense?
Example of the Interface:

interface Person {
    firstName: string;
    lastName: string;
    age: number;
}

That’s all! Okay, but how we can use it? The simplest example:

We’ve got a function which takes an object as an argument, e.g.:

function sayHello(person) {
    return `Hello, my name is ${person.firstName} ${person.lastName}!`;
}

and we need to set type of the argument. We can do it like this:

function sayHello(person: { firstName: string; lastName: string }) {
    return `Hello, my name is ${person.firstName} ${person.lastName}!`;
}

sayHello({ firstName: 'John', lastName: 'Doe' }); // Hello, my name is John Doe!

But also we can do it like this – with Interfaces!

interface Person {
    firstName: string;
    lastName: string;
    age: number;
}

function sayHello(person: Person) {
    return `Hello, my name is ${person.firstName} ${person.lastName}!`;
}

sayHello({ firstName: 'John', lastName: 'Doe', age: 20 }); // Hello, my name is John Doe!

Much better.

Now you know how an interface works and how to use it, but you need some tips for special use cases.

Optional types

Let’s talk about optional types. We’ve got an Interface Person which has the property ‘age’. Imagine a situation when a function doesn’t need the age of a person at all, yet the interface requires it. What then?
The answer is simple, just add a question mark to the property, like that:

interface Person {
    firstName: string;
    lastName: string;
    age?: number;
}

Now Typescript knows that ‘age’ is an optional property.

function sayHello(person: Person) {
    return `Hello, my name is ${person.firstName} ${person.lastName}!`;
}

sayHello({ firstName: 'John', lastName: 'Doe' }); // Hello, my name is John Doe!

Everything works!

Arrays in Typescript

How can w define an array in Interfaces? It’s easy.

interface Person {
    dogs: string[],
}

Okay, but what means “string[]”? It means the dog’s field will be an array of strings. Let me give you an example.

const John: Person = {
    dogs: ['Charlie', 'Max'],
};

What if we want to define an array of objects? It’s also easy.

At first, we need to create an Interface for the object:

interface Dog {
    name: string;
    age: number;
}

And use it in other Interface.

interface Person {
    dogs: Dog[];
}

const John: Person = {
    dogs: [{ name: 'Charlie', age: 4 }, { name: 'Max', age: 6 }],
};

Read-only properties

Okay, what are these? These properties are read-only, which means that their prefixes cannot be changed. We can assign value only once when we initialize them. E.g.:

interface Car {
    readonly productionYear: number;
    name: string;
}

Now Typescript will protect us from changing the value of productionYear.

Another useful thing is extending Interfaces. It means you can combine two Interface into one. It is very useful because you don’t need to write one big interface which is not reusable. Instead, you can build small reusable “blocks” and merge them into one.

interface Processor {
    processorName: string;
    cores: number;
}

interface Motherboard {
    motherboardName: string;
}

interface Computer extends Processor, Motherboard {
    // other properties
}

Type aliases

Basically Type aliases are very similar to Interfaces. We also can think that Type alias is like object of types(like in Interfaces), but not completely.

Take a look:

type Person = {
    firstName: string;
    lastName: string;
}

It looks like an Interface, but with the Type alias we can define a type like that:

type Age = number;
let age: Age = 23;

Type alias also can be extended like Interface:

type Computer = {
    fullPrice: number;
}

type Processor = Computer & {
    cores: number;
}

There is a lot of posts like “Type alias vs Interfaces”, I will show you the main differences.

We can add new fields to an existing Interface, but we can’t do this in a type alias. E.g.:

interface Person {
    firstName: string;
}

interface Person {
    lastName: string;
}
// Everything works

type Person = {
    firstName: string;
}

type Person = {
    lastName: string;
}
// Error

Another one is just syntax 🙂 Yes, a lot of posts are outdated, in the latest versions of TypeScript Type alias and Interfaces are becoming more and more similar.
As you can see in the official docs “Almost all features of an interface are available on in type.”

Bonus:
You can combine two interfaces into one type alias. E.g.:

interface Processor {
    processorName: string;
    cores: number;
}

interface Motherboard {
    motherboardName: string;
}

type Computer = Processor & Motherboard;

Generic types

Sometimes you have a function whose arguments can be a string, numbers, etc. and you want to build full reusable code, but… How can you do that? The answer is simple, generic types.

Take a look:

function myFunc<T>(arg: T): T {
    return arg;
}

It’s a function with generic types. Now we can assign this function to a variable with a specific type.

const myResult = myFunc<string>('hello');

You’d probably ask “okay, but why not to use any type?”, because when you use generic types you have control over your code. Type ‘any’ can accept everything, and believe me, you don’t want to overuse it… besides it’s ugly.

You also can use generics in Interfaces, Classes, etc.

As you can see, generic types give us many opportunities.

I hope you enjoyed this post, good luck with advanced TypeScript types! In the next post, I will show you how to use TypeScript with the new version of VueJS framework.

Author

Kacper Malkowski

Kacper is a Frontend Developer, but he is not afraid of backend adventures. His interests include both frontend and backend development, machine learning, and astronomy.

Leave a Reply

Your email address will not be published. Required fields are marked *


 

Newsletter