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 delete Expressions with Computed Key Expressions
Using delete
to remove computed key expressions is a bad idea.
It’s not secure and it can’t be optimized.
So instead of writing:
delete foo[bar];
We can just leave the object as is.
No Empty Blocks
We shouldn’t have empty blocks in our code.
They’re useless.
For instance, we should remove code like:
function foo(){}
No Floating Promises
Floating promises re promises that aren’t storing or returning any data.
Therefore, it’s not actually doing anything.
For instance, if we have:
Promise.resolve(1);
Then we should do something with it.
Unhandled promises can lead to unexpected behavior since they give us a value in an indeterminate amount of time.
Don’t Use for-in Loops with Arrays
We shouldn’t use for-in loops with arrays. It’s meant to be used with regular objects.
The order of iteration isn’t guaranteed.
So instead of using for-in like:
for (const i in array){
console.log(array[i]);
}
We can write:
for (const a of array){
console.log(a);
}
We replaced in
with of
and a
for the array item.
Now we can loop through them easily in order.
No Inferred Empty Object Type
We shouldn’t have empty object types since we should have a more specific type for our variables, parameters, and return types.
Instead of writing:
const obj: {} = {};
We write:
const obj: { foo: number } = { foo: 2 };
No Invalid this
We shouldn’t use this
outside of classes or object literals.
It just causes confusion since this
is supposed to be a class instance.
For instance, we can write:
const obj = {
a: 1,
b() {
console.log(this.a)
}
}
or:
class Foo {
constructor() {
this.a = 1;
}
bar() {
console.log(this.a)
}
}
No null Keyword
We should just use undefined
for all empty values instead of mixing null
or undefined
.
They serve the same purpose so we don’t need both.
undefined
also has type undefined
so it’s easier to check it.
Therefore, just use undefined
everywhere in our code.
No null and undefined Union Types
Creating a type with null
and undefined
is redundant.
This is because our variable, parameter or returned value can just have null
or undefined
or any other we specified.
We should make the type more restrictive so that we can actually take advantage of the type checking capability of TypeScript.
No Object Literal Type Assertion
Having type assertion with object literal types will hide errors with excess properties.
Even if the object is missing some required fields, the data type assertion will override whatever type it has without the assertion.
Therefore, we should deal with it without forcing the type to be an object literal structure.
So we shouldn’t write:
const foo = {} as { bar: number };
We write:
const foo: Foo = {};
where Foo
is an interface, type or type alias.
No Promise as Boolean
We shouldn’t use an await
expressions as a boolean expression.
await
only has a promise for giving the actual value in the future.
It’s not the actual value we want to check for.
Therefore, we should assign the await
ed value into a new variable so that we can do the check with the actual value.
For instance, instead of writing:
async function bar(personPromise: Promise<Person> ) {
if (await personPromise) {
console.log("person retrieved")
}
}
We write:
async function bar(personPromise: Promise<Person> ) {
const person = await personPromise;
if (person) {
console.log("person retrieved");
}
}
No Return Await
We shouldn’t use return
and await
on the same line.
It just adds extra time before the promise is resolved but the promise is returned no matter if there’s an await
or not.
For instance, instead of writing:
async function bar() {
return await aPromise;
}
We write:
async function bar() {
return aPromise;
}
Conclusion
delete
operator shouldn’t be used with the computed expression.
for-in loops shouldn’t be used with arrays.
this
should only be used for object literals and classes.
Literal type assertions shouldn’t be used to force the structure of the object.
await
should be used in certain places only in async
functions.