Table of Contents
- Why Code Quality Matters in TypeScript
- What Are Style Guides?
- Popular TypeScript Style Guides
- Linting Tools for TypeScript
- Setting Up Linting in a TypeScript Project
- Advanced Configuration Tips
- Integrating with Your Development Workflow
- Common Pitfalls and How to Avoid Them
- Conclusion
- 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 (
camelCasevs.snake_case), classes (PascalCase), constants (UPPER_CASE_SNAKE_CASE), etc. - Code Quality: Avoiding anti-patterns (e.g.,
anytype 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.
Popular TypeScript Style Guides
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
anyunless necessary). - Explicit return types for functions.
- Consistent naming conventions (e.g.,
interface Userinstead ofIUser). - 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
nullin favor ofundefined(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
constoverletfor 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-eslintadd 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: Encouragesas constfor type narrowing instead ofas 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-prettierto disable ESLint rules that conflict with Prettier, andeslint-plugin-prettierto 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:
-
Install Husky and
lint-staged(runs linting on staged files only):npm install --save-dev husky lint-staged -
Enable Husky hooks:
npx husky install echo "npx husky install" >> .git/hooks/post-checkout # Auto-enable Husky on repo clone -
Add a pre-commit hook:
npx husky add .husky/pre-commit "npx lint-staged" -
Configure
lint-stagedinpackage.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-prettierto 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 runtsc --noEmitin CI to catch type errors. - Outdated Plugins: Regularly update
@typescript-eslintand 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.