Categories
TypeScript Best Practices

TypeScript Best Practices -Useless Interfaces, Classes, and Promises

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 not writing empty interfaces.

Also, we should use promises in a useful way.

The any type also shouldn’t be used.

Also, classes shouldn’t be used as namespaces in TypeScript.

No Empty Interface Declarations

Empty interfaces aren’t very useful. Therefore, we probably don’t want them in our code.

So instead of writing:

interface Foo {}

or:

interface Baz extends Foo {}

We write:

interface Foo {
  name: string;
}

or:

interface Baz extends Foo, Bar {}

Extending 2 types inherit members from both types, so that may be useful.

Don’t use the any Type

The any type allows anything to be assigned to a variable in TypeScript.

Therefore, using the any type will bypass type checking for anything with that type.

To maximize the usefulness of the TypeScript compiler, we should add some types.

So instead of writing:

const foo: any = 'bar';

We can write:

const foo: string = 'bar';

Likewise, for arrays, if we have:

const arr: any[] = [1, 2];

We should write:

const arr: number[] = [1, 2];

instead.

For parameters, we write:

function greet(names: Array<string>): string {}

instead of:

function greet(names: Array<any>): string {}

We can make our types dynamic with union types, intersection types, and index signatures.

These are much better choices than using any .

No Extra Non-Null Assertion

We shouldn’t have non-null assertion that doesn’t add any extra value in our code.

For instance, if we have:

const bar = foo!!!.bar;

or:

function baz(bar?: { n: number }) {
  return bar!?.n;
}

Then the ! or there’s a nullable operator which cancels out the non-null operator or they’re redundant.

Instead, we should make our non-null operator useful by writing:

const bar = foo!.bar;

Don’t Use Classes as Namespaces

Classes shouldn’t be used as namespaces.

In TypeScript, we can put code other than classes at the top-level, so we can just do that instead of wrapping them in a class.

For instance, instead of writing:

class Foo {
  constructor() {
    foo();
  }
}

or:

class AllStatic {
  static num = 42;
  static greet() {
    console.log('Hello');
  }
}

We can write:

class Foo {
  constructor() {
    foo();
  }

  bar(){}
}

or:

class Bar {
  num = 42;
  greet() {
    console.log('Hello');
  }
}

We should have some instance methods or fields so that we actually need to create a class.

If we only have static variables, then we should create an object literal.

If we have an empty class or a class with only a constructor, then we don’t need the class.

Require Promise-Like Values to Be Handled Properly

We should handle promise-like values properly.

So if we have a promise in our code, we should use await in an async function and catch block to catch errors.

Or we call then on a promise, then we should call catch and/or finally on it to catch errors.

For instance, instead of writing:

const promise = new Promise((resolve, reject) => resolve('foo'));

or:

const foo = async() => {
  return 'value';
}

or:

Promise.reject('error').catch();

or:

Promise.reject('error').finally();

We should write:

const promise = new Promise((resolve, reject) => resolve('value'));
await promise;

or:

const foo = async () => {
  return 'value';
}
foo().then(
  () => {},
  () => {},
);

or:

Promise.reject('error').catch(() => {});

or:

Promise.reject('error').finally(() => {});

If our promise returns a value by resolving or rejecting, then we should handle them.

Otherwise, we may not need the promise to be present in our code.

Conclusion

We should use promises in a useful way in our code. Otherwise, we should remove them.

Classes shouldn’t be used as namespaces since we can put code at the top level.

Finally, we shouldn’t have empty interfaces in our 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 *