typescript
/

TypeScript Linting – ESLint & Code Quality Tools

Last Sync: Today

On this page

13
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

typescript

TypeScript Linting – ESLint & Code Quality Tools

Why Linting Matters in TypeScript

Linting helps catch errors, enforce coding standards, and maintain code quality across teams. While TypeScript provides type checking, linters catch stylistic issues, potential bugs, and enforce best practices.

Setting Up ESLint for TypeScript

BASHRead-only
1
# Install dependencies
npm install --save-dev eslint @eslint/js typescript-eslint

# Initialize ESLint configuration
npm init @eslint/config@latest

# Or manual setup for TypeScript
npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin

ESLint Configuration (Flat Config)

JavaScriptRead-only
1
// eslint.config.js (ESLint 9+ flat config)
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';

export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    rules: {
      '@typescript-eslint/no-explicit-any': 'error',
      '@typescript-eslint/explicit-function-return-type': 'warn',
      '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
      '@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
    },
  },
  {
    ignores: ['dist/**', 'node_modules/**', '*.config.js'],
  }
);

Legacy ESLint Configuration (rc format)

JSONRead-only
1
// .eslintrc.json (legacy)
{
  "parser": "@typescript-eslint/parser",
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "plugins": ["@typescript-eslint"],
  "rules": {
    "@typescript-eslint/no-explicit-any": "error",
    "@typescript-eslint/explicit-function-return-type": "warn",
    "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }]
  }
}

Essential TypeScript ESLint Rules

RuleDescriptionRecommended
@typescript-eslint/no-explicit-anyDisallow 'any' typeerror
@typescript-eslint/no-unsafe-assignmentPrevent unsafe type assignmentserror
@typescript-eslint/explicit-function-return-typeRequire return type annotationswarn
@typescript-eslint/consistent-type-definitionsEnforce interface over typewarn
@typescript-eslint/no-unused-varsCatch unused variableserror
@typescript-eslint/no-non-null-assertionDisallow '!' assertionswarn
@typescript-eslint/ban-ts-commentBan @ts-ignore commentswarn
@typescript-eslint/array-typeEnforce consistent array typeswarn

Prettier Integration

BASHRead-only
1
# Install Prettier and ESLint plugin
npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier

# Create .prettierrc
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 100
}
JavaScriptRead-only
1
// eslint.config.js with Prettier
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import prettier from 'eslint-plugin-prettier';
import eslintConfigPrettier from 'eslint-config-prettier';

export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    plugins: { prettier },
    rules: {
      ...eslintConfigPrettier.rules,
      'prettier/prettier': 'error',
      '@typescript-eslint/no-explicit-any': 'error',
    },
  }
);

Husky & Lint-Staged

BASHRead-only
1
# Install husky and lint-staged
npm install --save-dev husky lint-staged

# Setup husky
npx husky init

# Add pre-commit hook
echo "npx lint-staged" > .husky/pre-commit
JSONRead-only
1
// package.json
{
  "lint-staged": {
    "*.{ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{js,json,md}": [
      "prettier --write"
    ]
  },
  "scripts": {
    "lint": "eslint . --ext .ts,.tsx",
    "lint:fix": "eslint . --ext .ts,.tsx --fix",
    "format": "prettier --write ."
  }
}

VS Code Integration

JSONRead-only
1
// .vscode/settings.json
{
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "editor.formatOnSave": true,
  "eslint.validate": ["typescript", "typescriptreact"],
  "typescript.tsdk": "node_modules/typescript/lib"
}

Custom Rule Example

TypeScriptRead-only
1
// Custom ESLint rule - no-console-log
module.exports = {
  meta: {
    type: 'suggestion',
    docs: {
      description: 'Disallow console.log statements',
      recommended: false,
    },
    fixable: 'code',
  },
  create(context) {
    return {
      CallExpression(node) {
        if (
          node.callee.type === 'MemberExpression' &&
          node.callee.object.name === 'console' &&
          node.callee.property.name === 'log'
        ) {
          context.report({
            node,
            message: 'Unexpected console.log statement',
            fix(fixer) {
              return fixer.remove(node);
            },
          });
        }
      },
    };
  },
};

Common Linting Mistakes

  • Too many rules - Start with recommended configs and add gradually
  • Ignoring lint errors - Use CI to enforce linting pass
  • Not configuring Prettier - Let Prettier handle formatting, ESLint for code quality
  • Using outdated plugins - Keep @typescript-eslint packages updated
  • No type-aware linting - Enable parserOptions.project for advanced rules

Type-Aware Linting

JavaScriptRead-only
1
// eslint.config.js with type-aware rules
export default tseslint.config(
  ...tseslint.configs.recommendedTypeChecked,
  {
    languageOptions: {
      parserOptions: {
        project: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
    rules: {
      '@typescript-eslint/no-unsafe-argument': 'error',
      '@typescript-eslint/no-floating-promises': 'error',
      '@typescript-eslint/await-thenable': 'error',
    },
  }
);

Linting in CI/CD

YAMLRead-only
1
# .github/workflows/lint.yml
name: Lint

on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm run lint
      - run: npm run type-check
      - name: Check formatting
        run: npx prettier --check .

Conclusion

Linting is essential for maintaining TypeScript code quality. Use ESLint with typescript-eslint for code rules, Prettier for formatting, and tools like Husky to enforce standards before commits. Start with recommended configurations and customize based on your team's needs.

Try it yourself

// Try linting this code - many rules would trigger warnings!

// ❌ Using 'any' (no-explicit-any)
function processData(data: any) {
  return data.value;
}

// ❌ Unused variable (no-unused-vars)
const unusedVariable = 'hello';

// ❌ Missing return type (explicit-function-return-type)
function calculateSum(a: number, b: number) {
  return a + b;
}

// ❌ Non-null assertion (no-non-null-assertion)
const element = document.getElementById('app')!;

// ✅ Fixed version
interface Data {
  value: string;
}

function processDataFixed(data: Data): string {
  return data.value;
}

function calculateSumFixed(a: number, b: number): number {
  return a + b;
}

const elementFixed = document.getElementById('app');
if (elementFixed) {
  console.log('Element found!');
}

console.log('Linting would catch the issues above!');

Test Your Knowledge

Q1
of 4

Which package allows ESLint to lint TypeScript?

A
@typescript/eslint
B
typescript-eslint
C
eslint-typescript
D
tslint
Q2
of 4

What is the purpose of Prettier?

A
Type checking
B
Code formatting
C
Bundling
D
Testing
Q3
of 4

Which tool runs linters on staged git files?

A
Husky
B
lint-staged
C
pre-commit
D
eslint-staged
Q4
of 4

What does '@typescript-eslint/no-explicit-any' do?

A
Allows any type
B
Disallows any type
C
Converts any to unknown
D
Ignores any

Frequently Asked Questions

ESLint vs Prettier?

ESLint catches code quality issues; Prettier handles formatting. Use both together.

What is typescript-eslint?

A monorepo that allows ESLint to lint TypeScript code with type information.

How to disable a rule?

Use /* eslint-disable rule-name */ or configure in eslint.config.js.

What is type-aware linting?

Rules that use TypeScript's type information for deeper analysis.

Previous

ts build

Next

ts best practices

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.