Categories
TypeScript Best Practices

TypeScript Best Practices — Switches, Expressions, and Downcasting

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.

No String Literal Property Access

We shouldn’t use string literals to access properties if they’re valid identifiers.

For instance, instead of writing:

obj['prop']

We write:

obj.prop

But we can still use brackets to access properties that aren’t valid identifiers.

For instance, we can still write:

obj['foo-bar'];

No Throwing Strings

We shouldn’t throw strings since we toss out lots of information like the stack trace and the error type.

For instance, instead of writing:

throw 'error';

We write:

throw new Error("error");

No Switch Case Fallthrough

We shouldn’t have switch cases that don’t have a break or return statement.

For example, instead of writing:

switch (foo) {
  case 1:
    doWork(foo);
  case 2:
    doOtherWork(foo);
}

We write:

switch (foo) {
  case 1:
    doWork(foo);
    break;
  case 2:
    doOtherWork(foo);
    break;
}

No Tautology Expressions

We shouldn’t compare a value with itself.

They always run or don’t run.

For instance, instead of writing:

3 === 3

We write:

val === 3

No Assignment to this

We shouldn’t assign this to a value.

If we need to do that, we should use arrow functions instead.

So instead of writing:

const self = this;

setTimeout(function() {
  self.work();
});

We write:

setTimeout(() => {
  this.work();
});

No Unbound Method

We shouldn’t use instance methods outside a method call.

For instance, instead of writing:

class Foo {
  public log(): void {
    console.log(this);
  }
}

Foo.log();

We write:

class Foo {
  public log(): void {
    console.log(this);
  }
}

const foo = new Foo();
foo.log();

We can also write an arrow function and use bind if we don’t need to reference the class instance:

class Foo {
  public log = (): void => {
    console.log(foo);
  }
}

`const foo = new` Foo`();
foo.`log()`;`

or:

class Foo {
  public log() {
    console.log(this);
  }
}

const foo = new Foo();
const manualLog = foo.log.bind(foo);
manualLog.log();

No Unnecessary Class

We can put lots of things outside of classes.

For instance, we can have top-level functions and variables that aren’t contained in a class.

No Unsafe any Casts

We shouldn’t cast any variable or value to any .

This means it can contain anything.

If it has dynamic properties, we can use index signatures, union or intersection types, and more.

Instead of casting to any :

const foo = bar as any;

We can write:

interface Bar {
  [key: string]: string | number;
  [index: number]: string;
  baz: number;
}

const foo: Bar = bar;

We have baz and other dynamic properties in the Bar interface.

No Unsafe finally

We shouldn’t have return , continue , break or throws in finally blocks since they override the control flow statements of the try and catch blocks.

For instance, instead of writing:

try {
  doWork();
}
catch(ex) {
  console.log(ex);
}
finally {
  return false;
}

We write:

try {
  doWork();
  reutrn true;
}
catch(ex) {
  console.log(ex);
  return false;
}

No Unused Expression

We shouldn’t have any unused expression statements in our code.

For instance, instead of writing:

a === 1

We remove them or use them in statements.

No Using Variables Before Declaring Them

We shouldn’t use variables declaring them.

This is possible with var , but throws errors with let and const .

Instead of writing:

console.log(x);
var x = 1;

We write:

var x = 1;
console.log(x);

let y = 2;
console.log(y);

const z = 3;
console.log(z);

No var Keyword

We should think twice about using the var keyword.

Instead of using var , which has a tricky function scope and hoisting, we use let and const which are block-scoped and no tricky scoping issues.

For example, instead of writing:

var x = 2;

We write:

let a = 1;
const bar = 3;

Conclusion

We should access properties with the dot notation whenever possible.

Also, we should use the modern syntax for declaring variables.

Downcasting to any is also not good since we can assign anything to it.

We should also have break or return in our case blocks.

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 *