javascriptroom guide

TypeScript: Style Guides and Linting Tools for Improved Code Quality

TypeScript has revolutionized JavaScript development by adding static typing, enabling better tooling, and reducing runtime errors. However, even with TypeScript’s type safety, maintaining consistent code quality across teams and projects remains a challenge. Inconsistent formatting, ambiguous naming conventions, and hidden anti-patterns can lead to unreadable code, increased technical debt, and slower collaboration. This is where **style guides** and **linting tools** come into play. Style guides establish rules for writing code (e.g., indentation, naming conventions), while linting tools automate enforcement of these rules, catching issues early in the development process. Together, they ensure code is not only *correct* but also *consistent*, *readable*, and *maintainable*. In this blog, we’ll explore the importance of code quality in TypeScript, dive into popular style guides, compare key linting tools, and walk through setting up a robust linting workflow. By the end, you’ll have the tools to enforce clean, consistent code in your TypeScript projects.

Table of Contents

  1. Why Code Quality Matters in TypeScript
  2. What Are Style Guides?
  3. Popular TypeScript Style Guides
  4. Linting Tools for TypeScript
  5. Setting Up Linting in a TypeScript Project
  6. Advanced Configuration Tips
  7. Integrating with Your Development Workflow
  8. Common Pitfalls and How to Avoid Them
  9. Conclusion
  10. References

Why Code Quality Matters in TypeScript

TypeScript’s static typing helps catch type-related errors early, but it doesn’t solve all code quality issues. Here’s why investing in style guides and linting matters:

  • Consistency: Teams with diverse backgrounds write code differently. A shared style guide ensures everyone follows the same rules, making code easier to read and maintain.
  • Collaboration: Consistent code reduces onboarding time for new team members and minimizes debates over formatting during code reviews.
  • Error Reduction: Linting tools flag anti-patterns (e.g., unused variables, unsafe type assertions) and enforce best practices, preventing bugs before they reach production.
  • Scalability: As projects grow, unmaintained code becomes a liability. Automated linting ensures quality standards are enforced even as the codebase expands.

What Are Style Guides?

A style guide is a set of rules that define how code should be written and formatted. It covers:

  • Formatting: Indentation (spaces vs. tabs), line length, semicolons, quotes (single vs. double), and brace placement.
  • Naming Conventions: How to name variables (camelCase vs. snake_case), classes (PascalCase), constants (UPPER_CASE_SNAKE_CASE), etc.
  • Code Quality: Avoiding anti-patterns (e.g., any type overuse), enforcing type safety, and promoting readability (e.g., limiting function length).

Style guides are often paired with linting tools, which automate rule enforcement. This combination ensures compliance without manual effort.

Let’s explore the most widely adopted style guides for TypeScript and how to use them.

Airbnb TypeScript Style Guide

The Airbnb TypeScript Style Guide is one of the most popular choices, known for its strict, opinionated rules and focus on readability. It extends Airbnb’s JavaScript style guide with TypeScript-specific best practices.

Key Features:

  • Strict typing (e.g., avoiding any unless necessary).
  • Explicit return types for functions.
  • Consistent naming conventions (e.g., interface User instead of IUser).
  • Rules for React/TypeScript (if using React).

Adopting Airbnb:
Install the official ESLint config:

npm install --save-dev eslint-config-airbnb-typescript  

Extend it in your ESLint config (see Setting Up Linting for details).

Google TypeScript Style Guide

The Google TypeScript Style Guide is Google’s internal standard, designed for large-scale projects. It’s opinionated and emphasizes clarity and maintainability.

Key Features:

  • Requires explicit type annotations for function parameters and return types.
  • Discourages null in favor of undefined (or using optional chaining ?.).
  • Strict rules for generics and utility types.

Adopting Google:
Use the eslint-config-google package (note: it’s less actively maintained than Airbnb but still viable for Google-style projects).

Standard TypeScript Style Guide

The Standard Style Guide takes a “no configuration” approach, aiming to eliminate bikeshedding (arguments over trivial style choices).

Key Features:

  • No semicolons (;).
  • Spaces over tabs (2 spaces).
  • Single quotes ('hello' instead of "hello").
  • Automatic fixing of most style issues.

Adopting Standard:
Install the TypeScript variant:

npm install --save-dev eslint-config-standard-with-typescript  

Idiomatic TypeScript

The Idiomatic TypeScript guide, created by Matt Pocock, focuses on TypeScript-specific idioms and “TypeScript-first” best practices. It’s less about formatting and more about writing idiomatic, type-safe code.

Key Features:

  • Preferring const over let for immutability.
  • Using type inference wisely (avoiding redundant annotations).
  • Leveraging TypeScript’s advanced features (e.g., mapped types, template literals).

Adopting Idiomatic TypeScript:
While there’s no official ESLint config, you can manually enforce its rules using @typescript-eslint (see Advanced Configuration).

Linting Tools for TypeScript

Linting tools scan your code for style violations and code quality issues. Here are the tools you need to know.

ESLint + @typescript-eslint

ESLint is the de facto standard for linting JavaScript and TypeScript. It’s highly extensible via plugins and configs.

Why ESLint for TypeScript?

  • Extensibility: Plugins like @typescript-eslint add TypeScript-specific rules (e.g., no-explicit-any, typedef).
  • Active Community: Regular updates and a large ecosystem of plugins (e.g., React, Jest) make it versatile.

@typescript-eslint is the official ESLint plugin for TypeScript. It parses TypeScript code, provides type-aware linting, and includes rules like:

  • no-unused-vars: Flags unused variables (including TypeScript-specific ones like type parameters).
  • explicit-module-boundary-types: Requires return types for exported functions.
  • prefer-as-const: Encourages as const for type narrowing instead of as Type.

TSLint (Deprecated)

TSLint was once the primary linter for TypeScript but was deprecated in 2019. The TypeScript team now recommends ESLint with @typescript-eslint due to ESLint’s superior architecture and plugin ecosystem. Avoid TSLint for new projects.

Prettier: The Formatter

Prettier is not a linter—it’s a code formatter. It focuses on how code looks (indentation, line breaks) rather than how it works. Unlike ESLint, Prettier has few configurable rules; it enforces a consistent style with minimal setup.

Why Use Prettier with ESLint?

  • ESLint handles code quality (e.g., unused variables), while Prettier handles formatting (e.g., line length).
  • They complement each other: Use eslint-config-prettier to disable ESLint rules that conflict with Prettier, and eslint-plugin-prettier to run Prettier as an ESLint rule.

Setting Up Linting in a TypeScript Project

Let’s walk through setting up ESLint, @typescript-eslint, and Prettier in a TypeScript project.

Step 1: Project Setup

Initialize a new TypeScript project (or use an existing one):

mkdir ts-linting-demo && cd ts-linting-demo  
npm init -y  
tsc --init  # Generates tsconfig.json  

Step 2: Install Dependencies

Install TypeScript, ESLint, and related plugins:

npm install --save-dev typescript  
npm install --save-dev eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser  

Install Prettier and integration tools to avoid conflicts with ESLint:

npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier  

Step 3: Configure ESLint

Create an ESLint config file (.eslintrc.js) in your project root:

module.exports = {  
  root: true,  
  parser: '@typescript-eslint/parser',  // Parse TypeScript code  
  parserOptions: {  
    project: './tsconfig.json',  // Enable type-aware linting  
    tsconfigRootDir: __dirname,  
  },  
  plugins: ['@typescript-eslint', 'prettier'],  // Use TypeScript and Prettier plugins  
  extends: [  
    'eslint:recommended',  // Base ESLint rules  
    'plugin:@typescript-eslint/recommended',  // Recommended TypeScript rules  
    'plugin:@typescript-eslint/recommended-requiring-type-checking',  // Strict type-aware rules  
    'plugin:prettier/recommended',  // Disable ESLint formatting rules and run Prettier  
  ],  
  rules: {  
    // Custom rule overrides (example: allow console.log in development)  
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',  
    // TypeScript-specific rule: disallow 'any' type  
    '@typescript-eslint/no-explicit-any': 'error',  
  },  
};  

Step 4: Configure Prettier

Create a Prettier config file (.prettierrc) to define formatting rules:

{  
  "semi": true,  
  "singleQuote": true,  
  "tabWidth": 2,  
  "printWidth": 100,  
  "trailingComma": "es5"  
}  

Add a .prettierignore file to exclude files from formatting:

node_modules/  
dist/  
*.d.ts  

Step 5: Add Scripts to package.json

Add linting and formatting scripts to package.json:

{  
  "scripts": {  
    "lint": "eslint . --ext .ts",  // Check for linting errors  
    "lint:fix": "eslint . --ext .ts --fix",  // Auto-fix fixable errors  
    "format": "prettier --write ."  // Format all files with Prettier  
  }  
}  

Now run the scripts:

npm run lint  # Check for issues  
npm run lint:fix  # Fix auto-fixable issues  
npm run format  # Format code  

Advanced Configuration Tips

Custom Rules

Override or add rules in .eslintrc.js to tailor linting to your project:

rules: {  
  // Allow unused variables starting with '_' (e.g., _id)  
  '@typescript-eslint/no-unused-vars': ['error', { 'argsIgnorePattern': '^_' }],  
  // Require explicit return types for functions  
  '@typescript-eslint/explicit-function-return-type': 'error',  
}  

Ignoring Files

Use .eslintignore to exclude files/directories from linting:

node_modules/  
dist/  
src/**/*.test.ts  // Ignore test files (if using a separate test linter)  

Shareable Configs

For multiple projects, create a shareable ESLint config (e.g., @your-company/eslint-config-ts). Publish it to npm and reuse it across projects by extending it in .eslintrc.js.

Integrating with Your Development Workflow

Linting is most effective when integrated into your daily workflow.

IDEs (VSCode, WebStorm)

  • VSCode: Install the ESLint extension and enable auto-fix on save:
    Add to .vscode/settings.json:
    {  
      "editor.codeActionsOnSave": {  
        "source.fixAll.eslint": true  
      }  
    }  

Pre-Commit Hooks (Husky + lint-staged)

Use Husky to run linting before commits, ensuring code quality isn’t bypassed:

  1. Install Husky and lint-staged (runs linting on staged files only):

    npm install --save-dev husky lint-staged  
  2. Enable Husky hooks:

    npx husky install  
    echo "npx husky install" >> .git/hooks/post-checkout  # Auto-enable Husky on repo clone  
  3. Add a pre-commit hook:

    npx husky add .husky/pre-commit "npx lint-staged"  
  4. Configure lint-staged in package.json:

    {  
      "lint-staged": {  
        "*.ts": ["eslint --fix", "prettier --write"]  
      }  
    }  

CI/CD Pipelines (GitHub Actions, GitLab CI)

Enforce linting in CI/CD to block merges with code quality issues. Example GitHub Actions workflow (.github/workflows/lint.yml):

name: Lint  
on: [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  

Common Pitfalls and How to Avoid Them

  • ESLint/Prettier Conflicts: Always use eslint-config-prettier to disable ESLint formatting rules that clash with Prettier.
  • Overly Strict Rules: Start with recommended rule sets and gradually add strict rules (e.g., recommended-requiring-type-checking) to avoid overwhelming the team.
  • Ignoring Type Checking: Linting complements TypeScript’s compiler (tsc), but it doesn’t replace it. Always run tsc --noEmit in CI to catch type errors.
  • Outdated Plugins: Regularly update @typescript-eslint and ESLint plugins to avoid compatibility issues with TypeScript versions.

Conclusion

Style guides and linting tools are indispensable for maintaining high-quality TypeScript code. By adopting a shared style guide (like Airbnb or Standard) and automating enforcement with ESLint and Prettier, teams can write consistent, error-free code with minimal manual effort.

Remember: The goal isn’t perfection but consistency. Start small, integrate tools into your workflow, and iterate on rules as your project evolves. With the right setup, you’ll spend less time debating formatting and more time building great software.

References