header ad

Top 5 TypeScript Features You Should Master

Top 5 TypeScript Features You Should Master

Top 5 TypeScript Features You Should Master – The influence of TypeScript is expanding by the day. It’s become the go-to tool for any new web/Node project. The advantages of TypeScript are incalculable. However, it is critical to be aware of and comprehend all of the capabilities available to us in this JavaScript superset.

Do you put effort towards honing your Typescript skills? Are you attempting to make the best of the situation? There can be a lot of code duplication and boilerplate if you don’t use the correct TypeScript features and follow its best practices.

header ad

We’ll look at the five most essential things that TypeScript has to offer in this article. We can design a better and more complete codebase if we make sure we understand them and know their use cases.

1. Generics

How can we make our methods/APIs more reusable? Generics! This is a characteristic that almost all typed languages have. It allows us to represent types in a broader sense. This will give our classes and types more strength.

Let’s begin with a simple example. Create the following method to add any defined types to an array:

function addItem(item: string, array: string[]) {
  array = [...array, item];
  return array;
}

What if we wanted to make a similar utility for an int type? Should we repeat the procedure? Instead of adding more boilerplate, we can reuse the code by just utilizing generics:

function addItem<T>(item: T, array: T[]) {
  array = [...array, item];
  return array;
}

addItem('hello', []);

addItem(true, [true, true]);

How can we keep T from employing types that we don’t want? For this, we can use the extends keyword:

header ad
function addItem<T extends boolean | string>(item: T, array: T[]) {
  array = [...array, item];
  return array;
}

addItem('hello', []);

addItem(true, [true, true]);

addItem(new Date(), []);
//      ^^^^^^^^^^
// Argument of type 'Date' is not assignable to parameter of type 'string | boolean'

We will be able to create comprehensive and dynamic interfaces for our types due to generics. They are a must-have component that must be incorporated into our daily work.

2. Unions

Unions are one of TypeScript’s most basic and straightforward features. They make it simple to mix different types into one. Types can be composed in a variety of ways, including intersection and union types.

function logIdentifier(id: string | number) {
  console.log('id', id);
}

They come in handy when we need to explain that a type is nullable:

function logIdentifier(id: string | undefined) {
  if(!id) {
    console.error('no identifier found');
  } else {
    console.log('id', id);
  }
}

Unions aren’t simply for undefined or primitive values. They can be applied to any form of interface.

interface Vehicle {
  speed: number;
}
interface Bike extends Vehicle {
  ride: () => void;
}
interface Plane extends Vehicle {
  fly: () => void;
}
function useVehicle(vehicle: Bike | Plane) {
  ...
}

How can we tell the difference between a Bike and a Plane given a union type like the one above? Using the feature of a discriminated union. Vehicles will be an enum that will be used as a property value.

Let’s have a look at how it affects our code:

enum Vehicles {
    bike,
    plane
}

interface Vehicle {
    speed: number;
    type: Vehicles;
}

interface Bike extends Vehicle {
    ride: () => void;
    type: Vehicles.bike;
}

interface Plane extends Vehicle {
    fly: () => void;
    type: Vehicles.plane;
}

function useVehicle(vehicle: Bike | Plane) {
    if (vehicle.type === Vehicles.bike) {
        vehicle.ride();
    }

    if (vehicle.type === Vehicles.plane) {
        vehicle.fly();
    }
}

We’ve just seen how unions are a basic yet effective tool with a few twists up its sleeve. Generics, on the other hand, are required if we want to describe types/interfaces in a more powerful and dynamic manner.

3. Tuples

What exactly are tuples? Let’s take a closer look at the definition:

Tuple types allow you to express an array with a fixed number of elements whose types are known, but need not be the same. For example, you may want to represent a value as a pair of a string and a number – Typescript Documentation

The most crucial point to remember is that those arrays have a defined length. A tuple can be defined in two ways:

  • Explicitly:
const array: [string, number] = ['test', 12];
  • Implicitly
const array = ['test', 12] as const;

The only difference is that the as const makes the array read-only, which I believe is better.

Tuples can also be labelled:

function foo(x: [startIndex: number, endIndex: number]) {
  ...
}

When destructuring, labels do not need us to rename our variables. They exist solely for the sake of documentation and tools. Labels will make our code easier to read and maintain.

When utilizing labelled tuples, keep in mind that when one element is labelled, all other items in the tuple must be labelled as well.

4. Mapped Types

What exactly are mapped types? They’re a technique to prevent having to define interfaces repeatedly. You can save yourself time by basing a type on another type or interface.

Mapped types build on the syntax for index signatures, which are used to declare the types of properties which has not been declared ahead of time

To summarize, we can use mapped types to generate new types based on existing ones.

We don’t have to rewrite utility types in each project because TypeScript comes with a lot of them. Let’s take a look at a few of the more prevalent ones: Omit, Partial, Readonly, Readonly, Exclude, Extract, NonNullable, and ReturnType are all words that can be used to describe anything.

Let’s take a look at one of them in action. Let’s imagine we wish to make all of the properties of a Teacher entity readonly. What kind of utility can we make use of? The Readonly utility type can be used. Let’s take a look at how it works:

interface Teacher {
  name: string;
  email: string;
}

type ReadonlyTeacher = Readonly<Teacher>;

const t: ReadonlyTeacher = { name: 'jose', email: '[email protected]'};

t.name = 'max'; // Error: Cannot assign to 'name' because it is a read-only property.(2540)

Let’s have a look at how Readonly works from the inside out:

type Readonly<T> = { readonly [P in keyof T]: T[P]; }

Now it’s time to make our own utility for fun. To make a Writable type, reverse the Readonly type:

interface Teacher {
  readonly name: string;
  readonly email: string;
}

type Writeable<T> = { -readonly [P in keyof T]: T[P] };

const t: Writeable<Teacher> = { name: 'jose', email: '[email protected]' };

t.name = 'max'; // works fine

5. Type Guards

Type guards are a set of instruments that aid in the classification of items. As a result, we can move from a broad type to a more particular one.

Type guards can be performed in a variety of ways. We’ll concentrate on user-defined type guards in this post. Those are assertions, which are similar to functions for every given type.

What can we do with them? Simply define a function whose return type is a type predicate and which returns true or false. Let’s look at how we can make a type guard function out of a typeof operator:

function isNumber(x: any): x is number {
  return typeof x === "number";
}

function add1(value: string | number) {
  if (isNumber(value)) {
     return value +1;
  }
  return +value + 1;
}

Note that if the isNumber check is false, TypeScript can assume that value will be a string since x could be string or number.

Let’s have a look at another type guard that makes use of a custom interface:


interface Hunter {
    hunt: () => void;
}

// function type guard
function isHunter(x: unknown): x is Hunter {
    return (x as Hunter).hunt !== undefined;
}

const performAction = (x: unknown) => {
  if (isHunter(x)) {
    x.hunt();
  }
}

const animal = {
  hunt: () => console.log('hunt')
}

performAction(animal);

The return type of the isHunter function is x is Hunter. Our type guard will be that assertion function.

The type guards have been scoped. The x variable in the isHunter(x) code block is of type Hunter. As a result, we may confidently refer to it as a hunt method. The x type, however, will remain unknown outside of this code block.

Conclusion – Top 5 TypeScript Features You Should Master

We just went over the most important Typescript features available to us in this essay(Top 5 TypeScript Features You Should Master). We only touched the surface of them because this is only an overview.

My goal is to spark your interest and demonstrate Typescript’s capabilities. It’s up to you now to dive deep into any of them.

You’ll see how your code becomes more tidier, clearer, and easier to maintain as you try to gradually embrace them.

Leave a Comment

Your email address will not be published.