Esc
 Naviguer  Ouvrir Esc Fermer
Aller au contenu

11.3 — Outils statiques

🎯 Objectif : prévenir les bugs avant la prod en lisant le code statiquement. Linter, formatter, type-checker — la triade indispensable 2026.

À l'issue de cet axe, tu sauras :

  • Configurer ESLint v9 (flat config) avec Prettier
  • Choisir entre ESLint+Prettier et Biome
  • Activer TypeScript strict + noUncheckedIndexedAccess
  • Lancer PHPStan ou Psalm sur du PHP
  • Configurer Ruff + mypy sur Python
  • Mettre lint + typecheck en CI bloquante

Confirmé 10 min prérequis : axes 5-10 lus

3 outils complémentaires qui analysent ton code sans l’exécuter :

OutilDétecte
LinterBugs probables, mauvaises pratiques, code mort
FormatterIndentation, espaces, virgules — l’apparence
Type-checkerIncohérences de types

Tu veux les trois dans tes projets sérieux. Lancés en pre-commit + CI.

ESLint v9 (sortie 2024) introduit la flat config (eslint.config.js) qui remplace .eslintrc.

Fenêtre de terminal
npm install -D eslint @eslint/js typescript-eslint prettier
eslint.config.js
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
js.configs.recommended,
...tseslint.configs.strict,
{
rules: {
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'no-console': ['warn', { allow: ['warn', 'error'] }],
},
}
);
.prettierrc.json
{
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 100,
"arrowParens": "always"
}
// package.json — scripts
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
"typecheck": "tsc --noEmit",
"check": "pnpm lint && pnpm format --check && pnpm typecheck"
}
}

Biome = un seul binaire Rust qui fait linter + formatter + import organizer. 10-100× plus rapide qu’ESLint + Prettier.

Fenêtre de terminal
npm install -D @biomejs/biome
npx biome init
biome.json
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"linter": { "enabled": true, "rules": { "recommended": true } },
"formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2 }
}
Fenêtre de terminal
npx biome check # lint + format check
npx biome check --write # corrige

Ultra-rapide, un seul outil. ❌ Moins de règles que ESLint, certains plugins React/Vue/Astro pas encore au niveau.

Verdict 2026 : ESLint v9 + Prettier reste le défaut pour son écosystème. Biome gagne du terrain sur les projets qui priorisent la vitesse de feedback. Tu peux migrer plus tard.

PluginRôle
typescript-eslintTypescript-specific rules
eslint-plugin-reactReact
eslint-plugin-react-hooksDétecte les violations de règles des hooks
eslint-plugin-jsx-a11yAccessibilité JSX
eslint-plugin-importImports propres
eslint-plugin-vitestAnti-patterns de tests
eslint-plugin-tailwindcssConventions Tailwind
tsconfig.json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true
}
}

strict: true active 8 vérifications d’un coup :

  • noImplicitAny
  • strictNullChecks (le plus important — null/undefined explicites)
  • strictFunctionTypes
  • strictBindCallApply
  • strictPropertyInitialization
  • noImplicitThis
  • useUnknownInCatchVariables
  • alwaysStrict

noUncheckedIndexedAccess ajoute | undefined quand tu accèdes à arr[0] ou obj[key]. Plus sûr.

// Avec noUncheckedIndexedAccess
const arr = [1, 2, 3];
const first = arr[0]; // type: number | undefined
console.log(first.toFixed(2)); // ❌ erreur — peut être undefined
// Tu DOIS gérer le undefined :
if (first !== undefined) console.log(first.toFixed(2));
.github/workflows/ci.yml
- run: pnpm typecheck # tsc --noEmit

Bloque le merge si une erreur TS apparaît.

Ruff remplace Black + isort + Flake8 + pyupgrade + plein d’autres en un seul binaire Rust.

Fenêtre de terminal
uv add --dev ruff mypy
pyproject.toml
[tool.ruff]
line-length = 100
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "I", "B", "W", "UP"] # bug-prone, style, imports, etc.
[tool.ruff.format]
quote-style = "double"
[tool.mypy]
strict = true
python_version = "3.12"
Fenêtre de terminal
uv run ruff check . # lint
uv run ruff format . # format
uv run mypy . # type-check

PHPStan analyse statiquement le code PHP, détecte des bugs de types impossibles à exécuter.

Fenêtre de terminal
composer require --dev phpstan/phpstan
phpstan.neon
parameters:
level: 8 # 0 = laxiste, 9 = max strict
paths:
- src
excludePaths:
- tests
Fenêtre de terminal
vendor/bin/phpstan analyse

Niveau 8-9 = équivalent TypeScript strict. Permet d’attraper :

  • Méthodes appelées sur null.
  • Types incohérents.
  • Code mort.
  • Mauvaises annotations docblock.
Fenêtre de terminal
composer require --dev larastan/larastan laravel/pint

Pint est un formatter spécifique Laravel (basé PHP-CS-Fixer). Larastan étend PHPStan avec la connaissance Laravel (Eloquent, Facades).

Combo classique. Symfony fournit aussi symfony/phpstan-extension pour les helpers.

Pour forcer lint + format avant commit, sans dépendre de la discipline :

Fenêtre de terminal
npm install -D husky lint-staged
npx husky init
package.json
{
"lint-staged": {
"*.{ts,tsx,js,jsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,css}": ["prettier --write"]
}
}
.husky/pre-commit
npx lint-staged

À chaque git commit, seuls les fichiers stagés sont lintés/formatés. Rapide même sur gros repo.

pre-commit gère pareil pour Python :

.pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.4
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
Fenêtre de terminal
uv run pre-commit install
.github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '24' }
- run: npm ci
- run: npm run lint
- run: npm run typecheck
- run: npm run test -- --coverage
- run: npm run build

Chaque PR doit passer lint + typecheck + tests + build avant merge. Configuré en branch protection sur GitHub : on ne peut pas merger si la CI échoue.

Semgrep scanne du code multi-langage avec des règles type “regex sémantique”. Détecte des bugs de sécu et anti-patterns :

Fenêtre de terminal
npx semgrep --config=auto .
Fenêtre de terminal
npx gitleaks detect --no-git

À mettre en pre-commit + CI pour empêcher de commit accidentellement une clé API.

GitHub Dependabot ouvre automatiquement des PR quand une dépendance a une nouvelle version (sécurité ou minor). Renovate est l’alternative open source plus configurable.

sonarqube / codeclimate — scoring qualité globale

Section intitulée « sonarqube / codeclimate — scoring qualité globale »

Pour les projets enterprise, ces SaaS notent ton repo selon : couverture, duplication, complexité cyclomatique, tech debt.

Tu as `arr[0]` qui retourne `T | undefined` au lieu de `T`. Pourquoi ?
Tu fais `npm run lint` et tu as 200 erreurs sur un projet récupéré. Stratégie ?
Tu es en équipe de 5 devs. Chacun configure son ESLint différemment. Conséquence ?

Suite : 11.4 — Documentation — README, ADR, OpenAPI, Storybook.