Categories
TypeScript Best Practices

TypeScript Best Practices — Namespace, any, for-in and More

Spread the love

To make code easy to read and maintain, we should follow some best practices.

In this article, we’ll look at some best practices we should follow to make everyone’s lives easier.

Group Function Overloads Together

We can overload functions.

This means we can have multiple function signatures for a function, which TypeScript can check for.

To make our lives easier, we should group them together so that it’s easier to read:

function foo(a: string, b: string): string;

function foo(a: number, b: number): number;

function foo(a: any, b: any): any {
  console.log(a, b);
}

Visibility Declarations for Class Members

To take advantage of the access control capabilities of TypeScript, we can add the visibility declarations or class members.

For instance, we write:

class Employee {
  private getSalary(): number {
    return 90000;
  }
}

We added the private access modifier so that getSalary can only be called by other methods in the class.

There’s also the public modifier to make the member available to outside code.

protected makes the member available to subclasses and the current class.

public is the default.

We can also do the same for instance variables:

class Employee {
  private empCode: number;
}

Ordering Class Members

We may consider ordering class members to make the members easier to read.

We can order them by access modifiers, alphabetical order, etc.

It’s good to stick with one.

For instance, instead of writing:

class Employee {
  private id: string;
  private empCode: number;
  private empName: string;
}

We write:

class Employee {
  private empCode: number;
  private empName: string;
  private id: string;
}

to sort them by alphabetical order.

Eliminate the Use of any Types

We can eliminate the use of any types in our code to take advantage of TypeScript’s type-checking capabilities.

If we need something more flexible than static types, there are many ways to define them.

We can use literal types to restrict values to only some literals.

There’re union types to let us check for members for multiple types.

The intersection type makes sure that the variable has members that are in both types.

Index signatures let us check for dynamic properties.

There’re many ways to avoid any .

For instance, instead of writing:

let bar: any;

We write:

let foo: string;

No Empty Interface

We shouldn’t have empty interfaces in our code since they’re useless.

So instead of writing:

interface I {}

We write:

interface I {
  bar: number;
}

No for-in Loops

for-in loops are legacy JavaScript syntax which has better modern alternatives.

It’s bad since we need to use the hasOwnProperty to check for non-inherited properties with it.

Better alternatives include Object.keys to get the non-inherited keys of an object.

Object.values to get the values and Object.entries to get all entries.

So instead of writing:

for (const key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(obj[key]);
  }
}

We write:

for (const key in Oject.keys(obj)) {
  console.log(obj[key]);
}

No Import Side Effects

import should be used for import module members and using them.

If they perform side effects, then it’s not good because it’s hard to statically analyze the code.

So instead of writing:

import 'foo';

We write:

import { bar } from 'foo';

Some exceptions may be importing CSS with Webpack as modules.

So we may still write:

import 'styles.css';

No Explicit Type Declarations for Variable or Parameters with Literal Values

It’s redundant to have type declarations for variables or parameters that are assigned with numbers strings or boolean.

TypeScript can check these without an explicit type.

Therefore, instead of writing:

const foo: number = 10;

We write:

const foo = 10;

Don’t Use module Keyword for Namespaces

If we declare namespaces, then we should use the namespace keyword.

Instead of writing:

module Math {
  function add(a: number, b: number): number {
    return a + b;
  }
}

We write:

namespace Math {
  function add(a: number, b: number): number {
    return a + b;
  }
}

This way, we won’t confuse what we have with ES modules.

Conclusion

Grouping things together make them easier to read.

Visibility modifiers are a useful TypeScript feature.

any types can be replaced with many things.

Use namespace to declare namespaced code.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

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