Linting Your TypeScript Project Using TSLint
Usage of TypeScript's powerful type system decreases specific type of bugs. Linting tools provide additional static code analysis to spot common mistakes and ensure consistency across the large codebase. In each project team decides which of the rules generate an error. In this blog post, I'll cover how to setup a TSLint in your TypeScript project and show some example errors that TSLint spotted for us.
Installing TSLint on an existing project
I am not a big fan of global npm package installations; instead, I install TSLint as a devDependency. The local TSLint allows project members to have the same version on the current project and therefore the output is consistent across team members and build tools.
yarn add tslint --dev
yarn tslint --project ./tsconfig.json
The first line installs tslint as a devDependency. The second line run tslint using yarn, this way I don't have to write ./node_modules/.bin/tslint
. As I have an existing TypeScript project, I'll point tslint to the project configuration file.
Configuring TSLint
With init command I could create an empty configuration for the tslint. As an example, I use my current setting file.
{
"extends": [
"tslint:latest",
"tslint-config-prettier"
],
"rules": {
"ordered-imports": false,
"interface-name": [true, "never-prefix"],
"no-implicit-dependencies": [true, "dev"]
}
}
The configuration is a JSON file (by default it is named tslint.json). The JSON contains several keys, extends and rules being the most used ones.
In the example, I extend tslint's built-in configuration preset that contains latest recommended rules. When I update tslint, I might get additional errors compared to the previous version as new checks have been created that might be recommended.
I also use prettier and there is an NPM package that contains a configuration preset which will disable stylistic checks that prettier already fixes for me.
As this tslint-config-prettier is not built-in, I need to install it first.
yarn add tslint-config-prettier --dev
In the config file, the order of the extends array is significant. The latter line ("tslint-config-prettier") will override rules from the tslint:latest.
In the example configuration, I have disabled or changed some of the rules.
Rules
A rule is a single check that can be either built-in or a custom rule.
Lint rules encode logic for syntactic & semantic checks of TypeScript source code. --TSLint Rules page
Rules can have a configuration, for example, to provide exceptions to the rule or varying levels of strictness. If the rule has a configuration, then they have a schema.
prefer-object-spread is a straightforward rule that has no configuration. The prefer-object-spread check has a description "Enforces the use of the ES2015 object spread operator over Object.assign() where appropriate., " and the rationale section "Object spread allows for better type checking and inference."
In the picture below, I have used TSLint together with Visual Studio Code using a fantastic 3rd party extension.
Behind the scenes, the VS Code extension is using TSLint, so I would get the same error as using yarn tslint
command.
The screenshot has a light bulb, and by clicking it, I get a helpful context menu that allows me to fix the issue automatically! Again, this can also be done from the command-line.
prefer-object-spread is one of the rules that have an automatic fix available, rules with automatic fix can be identified from the list by looking for a keyword "Has Fixer."
If for some reason, I would like to disable that rule then I'll add a new property to the rules:
{
"extends": [
"tslint:latest",
"tslint-config-prettier"
],
"rules": {
"prefer-object-spread": false
}
}
Or, I can add a comment that in the next line I want to use Object.assign
instead of spread:
// tslint:disable-next-line:prefer-object-spread
Conclusion
Linting tools are not only useful for finding errors and providing consistency across codebase, but also linting tools are great for learning.
JavaScript and TypeScript allow me to do all sort of things, but that doesn't mean that it is wise to do even if possible. Example of a rule that tells something is possible, but not advisable or has a caveat is no-for-in-array rule. Also, there is a rule that looks for particular kind of bit operators as those are very rare in JavaScript projects and can be mixed with logical operators (for example, &
VS &&
). In our codebase, those bit operators were correctly used, so I marked them to be valid lines instead of disabling the rule.
Let me know if you have any questions.
Happy linting!