DEV Community

Cover image for TypeScript Best Practices
Bogdan Jiang
Bogdan Jiang

Posted on

TypeScript Best Practices

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

In this article, I am going to talk about some best practices you should follow to make everyone’s lives easier.

Group Function Overloads Together

You can overload functions.

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

To make your lives easier, you 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);
}

Ordering Class Members

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

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

It’s good to stick with one.

For example, instead of writing:

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

you write:

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

to sort them by alphabetical order.

Don’t Use module Keyword for Namespaces

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

Instead of writing:

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

You write:

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

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

Visibility Declarations for Class Members

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

For example, you write:

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

You 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.

You can also do the same for instance variables:

class Employee {
  private empCode: number;
}

Eliminate the Use of any Types

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

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

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

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

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

Index signatures let you check for dynamic properties.

There’re many ways to avoid any.

For example, instead of writing:

let bar: any;

you write:

let foo: string;

No Empty Interface

You shouldn’t have empty interfaces in your code since they’re useless.

So instead of writing:

interface I {}

You 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 you 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]);
  }
}

you 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';

you write:

import { bar } from 'foo';

Some exceptions may be importing CSS with Webpack as modules.
So you 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;

You write:

const foo = 10;

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 namespace code.

That’s it for today!

Thanks for your reading and stay tuned!

Oldest comments (1)

Collapse
 
suhakim profile image
sadiul hakim

gd.try to make code colourful.