TSLint is an extensible static analysis tool that checks Javascript and TypeScript code for readability, maintainability, and functionality errors.
TypeScript can be integrated into build systems and editors. It also has a set of core rules built into it and configuration that allows it to be extended with custom rules.
Many libraries have leveraged this configuration to build massive and wonderful tools out of it. The most popular among these is the Codelyzer, built by Minko Gechev.
The Codelyzer has custom rules that provide a way to lint Angular/TypeScript projects. The library is amazing, and we too can do the same.
Here, we will learn how to add our custom rules to the TSLint
.
Step 1. First, we create an empty project by typing the following commands in Command Prompt (CMD) or Powershell in Windows.
mkdir tslint-ext
cd tslint-ext
npm init -y
To install npm, refer to this documentation.
Step 2. Now, we install the dependencies.
npm i typescript tslint tsutils jest ts-jest @types/jest @types/node
Step 3. The "main"
file in our package.json
will be pointing to "index.js"
. Therefore, we create the index.js
file:
touch index.js
Step 4. Open the file and add the following code.
// ./index.js
module.exports = {
rulesDirectory: './',
}
We export the literal object as the default export. Inside it, we have a rulesDirectory
property with "./"
. This would tell tslint
that the custom lint rules are in the "./"
folder relative to this file.
We will write a custom rule that will enforce pascal-cased class names and interface names.
PascalCase
?PascalCase
is a naming convention in which the first letter of each word is capitalized.
We often use PascalCase
when writing function names, class names, interface names, and other objects.
PascalCase
is very helpful in distinguishing words within names, and helps developers write readable code.
Suppose we want users to configure our PascalCased
class names by adding “class-name-pascal-case”
to tslint.json
.
To begin, let’s create a file that will implement the PascalCase
rule:
touch classNamePascalCaseRule.ts
PascalCase
There are important conventions we have to know:
Rule identifiers are always kebab-cased.
Rule files are always camel-cased.
Rule files must contain the suffix Rule.
The exported class must always be named Rule
.
The exported class must extend Lint.Rules.AbstractRule
.
Our rule identifier is kebab-cased, i.e., “class-name-pascal-case”, so its Rule file must be named “classNamePascalCaseRule.ts” camel-cased with “Rule”, and suffixed.
Open the “classNamePascalCaseRule.ts” file and paste this code.
We need to hook up to tslint
. First, we compile it using tsc
.
tsc classNamePascalCaseRule.ts
This will generate classNamePascalCaseRule.js
in the same dir
as classNamePascalCaseRule.ts
.
Now, we have to hook up our custom rule in our project. We can publish this tslint-ext
to NPM
and import it as a dependency in any project that we want to use the custom rule in.
Step 1. Let’s publish the tslint-ext
to NPM
using:
npm publish
You have to be logged in
NPM
, and alsopush
tslint-ext
to Github before publishing.
Step 2. Now, we can install it via:
npm i tslint-ext -D
The -D
flag means to install it as a dev dependency.
Let’s say we have a project ts-prj
, and we want to use the class-name-pascal-case
in it.
ts-prj
src
...
node_modules
tslint.json
package.json
tsconfig.json
Step 1. First, we install the tslint-ext
module.
npm i tslint-ext -D
Step 2. Then, we open the tslint.json
file in the ts-prj
project.
{
"extends": "tslint:recommended",
"rules": {
"class-name-pascal-case": true
},
"rulesDirectory": [
"tslint-ext"
]
}
The two important settings here are that we specify the name of the dependency library in the “rulesDirectory” array property. Then we specify the rule name in the library that we want to use in the “rules” property.
Now, tslint
will use the “class-name-pascal-case”
when we lint the fields in the ts-prj
folder.
If we have a class in our project, read the following:
// ts-prj/component.ts
export class BARCHART_COMPONENT {}
We have a class BARCHART_COMPONENT
here. The name here is not pascal-cased, so when we run tslint
on it we will see the error "Class name must be in pascal case"
on our terminal.`
$ tslint -c tslint.json component.ts
Error at component.ts 3: Class name must be in pascal case
That’s it, our rule is run.
We can use the rule from the tslint-ext
folder without pushing
and installing it from NPM
.
We can create the tslint-ext
inside the ts-prj
:
ts-prj
tslint-ext/
...
src/
...
node_modules
tslint.json
package.json
tsconfig.json
Now, the tslint.json
will be this:
{
"extends": "tslint:recommended",
"rules": {
"class-name-pascal-case": true
},
"rulesDirectory": [
"tslint-ext"
]
}
If the tslint-ext
project is inside the ts-prj/src
folder, then the tslint.json
will be this:
{
"extends": "tslint:recommended",
"rules": {
"class-name-pascal-case": true
},
"rulesDirectory": [
"ts-prj/src/tslint-ext"
]
}
Running tslint
on component.ts
will still succeed.
$ tslint -c tslint.json component.ts
Error at component.ts 3: Class name must be in pascal case
Adding custom rules to tslint
is super easy. It just takes a few very careful configurations to get it right. Now, we know how popular custom linting libraries like Codelyzer work.
Free Resources