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.
Class Name Casing
TypeScript class names should be PascalCase.
This also applies to interfaces.
So we write:
class Foobar {}
and:
interface FooBar {}
Use UTF-8 Encoding for Files
We should use UTF-8 encoding for files.
This way, there won’t be any issues using the file anywhere.
File Name Casing
We should name our files with a consistent case.
We can stick with camel case, Pascal case, kebab case, or snake case.
Camel case is fileName.ts
.
Pascal case is FileName.ts
,
Kebab case is file-name.ts
.
Snake case is file_name.ts
.
We just stick with one for all files.
Use Explicit Increment or Decrement Operators
We should use explicit increment or decrement operators to make sure that we just assign the new value and don’t use the return value.
For instance, instead of writing:
++i;
i++;
--j;
j--;
which return the value and do the increment or decrement operation, we write:
i += 1;
i -= 1;
j += 1;
j -= 1;
Interface
We may want to have interfaces that start with I
to distinguish them from other entities.
For instance, we may want to write:
interface IFoo {
bar: string;
}
Use Interface Over Type Literal
Interfaces can be implemented, extended, and merged, so they’re preferred to type literals.
For instance, instead of writing:
type Alias = {
num: number
}
We write:
interface Foo {
num: number;
}
Match Default Export Name
If we have a default export, then our default import should match the name of the export.
This reduces confusion.
So if we have:
bar.ts
export default foo;
Then we write:
import foo from bar;
Newline Per Chained Call
If we have a chain of method calls, then we may want to put each of them in a new line so that it won’t overflow the page.
For instance, instead of writing:
foo.bar().baz();
We write:
foo
.bar()
.baz();
No Angle Bracket Type Assertion
We should use as
for type assertions since we can use it for type assertions in .tsx
files in addition to .ts
files.
So instead of writing:
const foo = <Bar>bar;
We write:
const foo = bar as Bar;
No Boolean Literal Comparison
We shouldn’t compare with boolean literals since they’re redundant.
For instance, we can shorten:
if (x === true)
to:
if (x)
Use of Parameter Properties
We can have parameter properties in the TypeScript code.
They let us pass in constructor
parameter and assign it to a value at the same time.
Instead of writing:
class Animal {
constructor(private numLegs: number) {}
}
We can write:
class Animal {
private numLegs: number = 2;
constructor(numLegs: number) {
this.numLegs = numLegs;
}
}
No Reference Import
We shouldn’t use reference
if we use import
.
For instance, if we have:
<reference path="foo.bar" />
We write:
import { bar } from 'foo';
It’s more standard and we don’t need reference
to pull type definitions out of type definition files anymore.
No Useless Callback Wrappers
We shouldn’t have useless callback wrappers in our code.
For instance, instead of writing:
const handleContent = (content) => console.log('do something with', content);
promise.then((content) => handleContent(content))
We write:
const handleContent = (content) => console.log('do something with', content);
promise.then(handleContent)
It’s a lot cleaner.
No Unnecessary Initializers
We shouldn’t have to set variables to undefined
.
For instance, instead of writing:
let x = undefined;
We write:
let x;
No Object Literal Key Quotes
If an object literal has valid identifiers as property names, then we don’t need quotes around the names.
For instance, instead of writing:
const obj = { 'foo': 1 };
We write:
const obj = { foo: 1 };
Conclusion
We should have a consistent file name casing.
Also, we shouldn’t have unnecessary syntax in our code.
Imports should be used to pull data type definitions instead from external sources.
Useless callback wrappers should also be removed.
Interfaces should be used instead of type alias since they’re more versatile.