Categories
TypeScript Best Practices

TypeScript Best Practices — Delimiters and Ordering

Spread the love

TypeScript is an easy to learn extension of JavaScript. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust TypeScript code.

In this article, we’ll look at the best practices to following when writing code with TypeScript, including delimiters for interfaces and type literals.

Also, we’ll look at consistency in declaration order, useless calls to toString , and bad uses the delete operator.

Require Specific Member Delimiter Style for Interfaces and Type Literals

In TypeScript, interfaces and type literals can have members separated by a comma or a semicolon.

It’s a good idea to have a consistent style.

For instance, we can write them all as follows:

interface Foo {
  name: string;
  bar(): void;
}

or we can write as follows:

interface Foo {
  name: string,
  bar(): void,
}

For type literals, we can write:

type Foo {
  name: string;
  bar(): void;
}

or:

type Foo {
  name: string,
  bar(): void,
}

They’re both valid, but TypeScript prefers semicolon.

Require a Consistent Member Declaration Order

It may be a good idea to order our members in interfaces, type literals, classes, and class expressions in a certain way.

This way, it’s easier to read as similar items are grouped together.

We can group the public and static fields together.

Or we can group protected and static fields together, for example.

Alternatively, we can group them alphabetically.

For instance, we can write:

class Foo {
  private foo: string;
  public bar: string;
  protected static baz: string;

  constructor() {}

  public static A(): void {}
  public B(): void {}

  [Z: string]: any;
}

We grouped the fields together at the top. Then we have the constructor.

Next, we have public methods.

Then we have the index signature to allow us to put in anything else.

Likewise, we can do the same for type literals:

interface Foo {
  [Z: string]: any;

  bar(): void;

  new ();

  baz: string;
}

We have our index signature, then a method, then the constructor, and finally the field.

These are just some possibilities for organizing members.

Enforce Particular Method Signature Syntax

We can enforce the syntax of method signatures in types and interfaces.

For instance, we can write:

interface Foo {
  foo(arg: string): number;
}

or we can write:

interface Foo {
  foo: (arg: string) => number;
}

We just have to keep one consistent type for better readability.

Enforce Naming Convention for Everything Across a Codebase

To make our code more predictable, we can enforce a naming convention across a whole project.

We can validate leading underscores, trailing underscores.

Also, we can check prefixes and suffixes.

The format can also be checked.

For casing, we should stick with the convention specified in JavaScript.

Therefore, we should stick with camelCase for variables and functions.

Constructor functions or classes should be PascalCase.

Constants that don’t change should be in upper case with underscores separating the words.

Parameters are also camelCase.

Enum cases are upper case while the name is PascalCase.

toString Should Only be Called on Objects to Provide Useful Information When Stringified

We should call toString to get some useful information on objects.

Therefore, if our object only inherits from Object ‘s prototype’s toString method, then we shouldn’t call it.

For instance, if we have an empty object, then we shouldn’t call toString on it, since it doesn’t give us anything useful:

{}.toString()

However, if our object has its own toString method:

const foo = {
  toString() {
    return "foo";
  }
};

const str = foo.toString();

then we can call it.

Disallow the delete Operator with Computed Key Expressions

Since deleting dynamically computed keys can be dangerous, we may want to not write that co0de.

For instance, we can write:

delete foo[prop];

and prop can be anything, so we may delete the property that we want to keep.

Conclusion

We may not want to use the delete operator to delete dynamic properties because we may delete the wrong thing.

Also, since Object ‘s prototype’s toString isn’t all that useful, we shouldn’t call it.

Having specific orders of members for literals may be good to make looking things up easier.

Also, method signature syntax may be written in a specific order for predictability.

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 *