TypeScript ESLint
Introduction
When writing TypeScript code, having tools that help you maintain code quality and consistency is essential. One of the most powerful tools for this purpose is TypeScript ESLint. ESLint is a popular static code analysis tool that identifies and fixes problems in JavaScript code, and when combined with TypeScript, it provides an even more robust system for maintaining high-quality TypeScript code.
In this guide, we'll explore how to set up, configure, and effectively use ESLint with TypeScript to improve your development workflow and code quality.
What is TypeScript ESLint?
TypeScript ESLint is the combination of:
- ESLint: A highly configurable linting utility for JavaScript
- typescript-eslint: A package that enables ESLint to understand TypeScript code
This combination allows you to:
- Catch syntax errors and potential bugs
- Enforce consistent coding styles
- Identify problematic patterns
- Apply TypeScript-specific best practices
- Integrate with your IDE for real-time feedback
Getting Started with TypeScript ESLint
Prerequisites
Before we begin, ensure you have:
- Node.js and npm installed
- A TypeScript project (or you're ready to create one)
Installation
Let's set up ESLint with TypeScript support:
# Create a new project if you don't have one
mkdir ts-eslint-demo
cd ts-eslint-demo
npm init -y
npm install typescript --save-dev
# Install ESLint and TypeScript ESLint packages
npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
Configuration
Create a .eslintrc.js
file in your project root:
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: [
'@typescript-eslint',
],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
],
rules: {
// Your custom rules here
}
};
This basic configuration:
- Specifies the TypeScript parser
- Adds the TypeScript ESLint plugin
- Extends the recommended ESLint and TypeScript ESLint rules
Key Concepts of TypeScript ESLint
1. Parser
The parser is responsible for converting your code into an Abstract Syntax Tree (AST) that ESLint can analyze:
// In .eslintrc.js
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
project: './tsconfig.json', // Points to your TypeScript configuration
},
2. Plugins
Plugins provide additional rules and functionality:
plugins: [
'@typescript-eslint',
// Other plugins you might use
],
3. Configurations (extends)
The extends
property allows you to import sets of pre-defined rules:
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
4. Rules
Rules define specific coding standards you want to enforce:
rules: {
'@typescript-eslint/explicit-function-return-type': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'semi': ['error', 'always'],
'quotes': ['error', 'single'],
},
Practical Examples
Let's look at how TypeScript ESLint can help you write better code.
Example 1: Type Safety
Consider this TypeScript code:
// Without TypeScript ESLint
function calculateTotal(items) {
let total = 0;
items.forEach(item => {
total += item.price * item.quantity;
});
return total;
}
const items = [
{ name: 'Shirt', price: 25, quantity: 2 },
{ name: 'Pants', price: 50, quantity: 1 }
];
const total = calculateTotal(items);
With TypeScript ESLint and appropriate rules, you would be prompted to add proper type annotations:
// With TypeScript ESLint
interface Item {
name: string;
price: number;
quantity: number;
}
function calculateTotal(items: Item[]): number {
let total = 0;
items.forEach(item => {
total += item.price * item.quantity;
});
return total;
}
const items: Item[] = [
{ name: 'Shirt', price: 25, quantity: 2 },
{ name: 'Pants', price: 50, quantity: 1 }
];
const total = calculateTotal(items);
ESLint would show errors for the first example if you have rules like @typescript-eslint/explicit-function-return-type
enabled.
Example 2: Code Style Consistency
ESLint helps maintain consistent code style:
// Inconsistent code
const getUserData = async(userId:string)=>{
const user = await fetchUser(userId);
if(user){
return {
name: user.name,
email:user.email
}
}
return null
}
With ESLint rules for spacing, indentation, and semicolons, you would be guided to write:
// Consistent code after ESLint fixes
const getUserData = async (userId: string): Promise<UserData | null> => {
const user = await fetchUser(userId);
if (user) {
return {
name: user.name,
email: user.email
};
}
return null;
};
Example 3: Preventing Common Errors
ESLint can catch potential bugs:
// Potential bug
function processArray(array: string[]): void {
for (let i = 0; i <= array.length; i++) {
console.log(array[i].toUpperCase());
}
}
// Fixed version after ESLint warning
function processArray(array: string[]): void {
for (let i = 0; i < array.length; i++) {
console.log(array[i].toUpperCase());
}
}
In the first example, the loop condition i <= array.length
would cause an error because arrays are zero-indexed, and ESLint could flag this with the appropriate rule.
Integrating with Your Development Workflow
Running ESLint from the Command Line
Add scripts to your package.json
:
"scripts": {
"lint": "eslint . --ext .ts,.tsx",
"lint:fix": "eslint . --ext .ts,.tsx --fix"
}
Then run:
npm run lint # Check for issues
npm run lint:fix # Fix automatically fixable issues
VSCode Integration
For real-time linting in VSCode:
- Install the ESLint extension
- Add these settings to your
.vscode/settings.json
:
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": ["javascript", "typescript"]
}
CI/CD Integration
Add ESLint checks to your continuous integration pipeline:
# Example GitHub Actions workflow
name: Lint
on: [push, pull_request]
jobs:
eslint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '14'
- run: npm ci
- run: npm run lint
Advanced Configuration
Using Shareable Configs
Shareable configs let you extend common rule sets:
npm install eslint-config-airbnb-typescript --save-dev
Update your .eslintrc.js
:
extends: [
'airbnb-typescript',
// Other configs...
],
Custom Rules
You can create project-specific rules:
rules: {
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'interface',
format: ['PascalCase'],
prefix: ['I']
}
],
// Additional custom rules...
}
Ignoring Files
Create a .eslintignore
file to exclude certain files or directories:
node_modules
dist
coverage
*.config.js
Common TypeScript ESLint Rules
Here are some useful TypeScript-specific rules:
Rule | Description |
---|---|
@typescript-eslint/explicit-function-return-type | Requires explicit return types on functions |
@typescript-eslint/no-explicit-any | Disallows usage of the any type |
@typescript-eslint/no-unused-vars | Prevents variables being declared but not used |
@typescript-eslint/no-non-null-assertion | Disallows non-null assertions using the ! postfix operator |
@typescript-eslint/await-thenable | Ensures that await is only used with Promises |
Troubleshooting Common Issues
ESLint Not Finding TypeScript Files
Make sure you're specifying the file extensions:
// In your ESLint command or configuration
"--ext .ts,.tsx"
Rules Not Working as Expected
Check that your configuration extends the correct rule sets and that your parser options are properly set:
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
Conflicts with Prettier
If you're also using Prettier, install the appropriate integration:
npm install eslint-config-prettier eslint-plugin-prettier --save-dev
Then update your .eslintrc.js
:
extends: [
// Other configs...
'plugin:prettier/recommended',
],
Summary
TypeScript ESLint is a powerful combination that enhances your TypeScript development experience by:
- Catching potential errors and bugs before runtime
- Enforcing consistent coding standards across your project
- Improving code readability and maintainability
- Providing real-time feedback in your IDE
By integrating ESLint into your TypeScript projects, you'll write cleaner, more robust code and catch issues early in the development process.
Additional Resources
Exercises
- Set up ESLint in a new TypeScript project and configure it with the recommended rules.
- Write a TypeScript function with intentional errors and use ESLint to identify and fix them.
- Create a custom ESLint rule that enforces a specific naming convention for your project.
- Configure ESLint to run automatically on your pre-commit git hooks using Husky.
- Experiment with different rule severity levels (error, warning, off) and observe how they affect your workflow.
By mastering TypeScript ESLint, you'll significantly improve your code quality and development efficiency!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)