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.