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 replacing for-in loops with better alternatives.
Promise code should also be useful.
eval-like Methods also shouldn’t be used.
No Iteration Over an Array with a for-in Loop
The for-in loop isn’t all that useful now that there are the for-of loops and methods to get object keys.
Also, it iterates over the prototypes of our object, which we probably don’t want.
The order of iteration also isn’t guaranteed.
Therefore, we shouldn’t use it in our code.
Instead of writing:
for (const x in [1, 2, 3]) {
console.log(x);
}
We write:
for (const x of [1, 2, 3]) {
console.log(x);
}
The for-in loop loops over the indexes, while the for-of loop loops over the entries.
Don’t Use eval-Like Methods
In JavaScript and by extension, TypeScript, both have methods that take strings and run them as code.
There’s the eval
method which runs code from a string.
The Function
constructor also returns a function from a string.
Also, setTimeout
and setInterval
functions can both run code from a string.
This prevents any optimization from being done since the code is in a string.
Also, it creates a big security flaw since anyone can input a string with code and run it potentially.
Therefore, we shouldn’t run any function that allows us to run code from string.
If we use setTimeout
or setInterval
, we should pass in a callback instead of a string.
For instance, instead of writing:
setTimeout('alert(`foo`);', 100);
or:
const add = new Function('a', 'b', 'return a + b');
We write:
setTimeout(() => {
alert(`foo`);
}, 100);
or:
setInterval(() => {
alert(`foo`);
}, 10000);
and don’t use the other functions.
No Explicit Type Declarations for Variables or Parameters Initialize to a number, string, or boolean
We don’t need types for anything that’s been explicitly assigned a number, string, or boolean.
This is because it’s obvious from the code what they are.
Therefore, instead of writing:
const a: number = 10;
We write:
const a = 10;
This applies to any other primitive values like string or boolean.
If the return type is obvious, then we can also skip the type annotation.
So, instead of writing:
const a: number = Number('1');
We write:
const a = Number('1');
This also applies to regexes. If we have a regex literal, then we don’t nee the annotation.
Instead of writing:
const a: RegExp = /foo/;
We write:
const a = /foo/;
Use new and constructor in Valid Ways
We should use new
and constructor
in valid ways.
Therefore, we shouldn’t use them for creating new class instances or as constructor functions respectively.
For instance, instead of writing:
class C {
new(): C;
}
We write:
class C {
constructor(){
//...
}
}
const c = new C();
Constructors should only be in classes.
We can also specify new
as a signature in interfaces:
interface I {
new (): C;
}
Don’t Use Promises in Places that aren’t Designed to Handle Them
We shouldn’t use promises in places that aren’t designed to handle them.
For instance, we shouldn’t put them in if
statements or loops.
So instead of writing:
const promise = Promise.resolve('foo');
if (promise) {
// Do something
}
or:
const promise = Promise.resolve('foo');
while (promise) {
// Do something
}
or:
[1, 2, 3].forEach(async value => {
await foo(value);
});
or:
new Promise(async (resolve, reject) => {
await doSomething();
resolve();
});
We should write:
const promise = Promise.resolve('foo');
if (await promise) {
// Do something
}
or:
const promise = Promise.resolve('foo');
while (await promise) {
// Do something
}
or:
for (const value of [1, 2, 3]) {
await foo(value);
}
We need to put await
in the right places so that we get the resolved value properly.
Also, the following isn’t valid:
new Promise(async (resolve, reject) => {
await doSomething();
resolve();
});
because it’s redundant to have a promise inside a promise.
We can move the await doSomething()
outside our promise callback.
Conclusion
Promises should be used in a useful manner or they shouldn’t be used at all.
eval-like functions shouldn’t be used because they’re dangerous.
for-in loops should be replaced with better alternatives.