Hier ein Plan zum Aufsetzten einer pre-commit hook, welcher best practices beschreibt:

# Pre-Commit Hooks fuer TypeScript Repositories — Best Practice

## Ueberblick

Automatische Code-Qualitaetspruefung vor jedem `git commit`. Geaenderte Dateien werden beim Commit automatisch gelintet und formatiert. Schlaegt eine Pruefung fehl, wird der Commit abgelehnt — der Entwickler fixt, staged erneut und committet nochmal.

**Ergebnis:** Einheitlicher Code-Style wird automatisch erzwungen, ohne dass jemand daran denken muss.

---

## Toolchain

| Tool | Aufgabe | Warum dieses Tool |
|------|---------|-------------------|
| **Husky** (v9+) | Git-Hook-Management | Registriert sich in `.git/hooks/`, wird automatisch bei `npm install` aktiviert (via `prepare`-Script). Kein manuelles Setup noetig. |
| **lint-staged** (v16+) | Filter fuer gestagte Dateien | Fuehrt Linter/Formatter nur auf Dateien aus, die tatsaechlich geaendert wurden — nicht auf dem gesamten Codebase. Schnell auch in grossen Repos. |
| **ESLint** (v10+) | Linting | Prueft TypeScript-Code auf Fehler, Bugs und Best-Practice-Verstoesse. Auto-Fix fuer viele Probleme. Nutzt Flat Config (`eslint.config.mjs`). |
| **Prettier** (v3+) | Formatting | Erzwingt einheitliche Formatierung (Einrueckung, Semikolons, Quotes etc.). Keine Diskussionen ueber Code-Style. |
| **typescript-eslint** | ESLint + TypeScript | Vereinheitlichtes Package fuer TypeScript-Unterstuetzung in ESLint. Ersetzt die alten separaten Packages `@typescript-eslint/eslint-plugin` und `@typescript-eslint/parser`. |

### Warum nicht Biome, dprint oder oxlint?

Husky + lint-staged + ESLint + Prettier ist der etablierte Standard im TypeScript-Oekosystem. Breite IDE-Unterstuetzung, grosse Community, gute Dokumentation. Neuere Tools wie Biome sind vielversprechend, aber noch nicht so ausgereift im Regelumfang.

---

## Architektur

repository-root/ ├── .husky/ │ └── pre-commit # Hook: ruft "npx lint-staged" auf ├── package.json # Husky + lint-staged + ESLint + Prettier als devDependencies ├── package-lock.json # Reproduzierbare Installs ├── lint-staged.config.mjs # Bestimmt welche Tools auf welche Dateien laufen ├── eslint.config.mjs # ESLint Flat Config (Regeln) ├── .prettierrc # Prettier Config (Formatierung) ├── .prettierignore # Dateien die Prettier ignorieren soll └── src/ # (oder Unterordner mit eigenem package.json)


### Ablauf bei `git commit`

git commit │ ▼ Husky triggert .husky/pre-commit │ ▼ npx lint-staged │ ├── Findet gestagte .ts Dateien │ ├── eslint --fix (Linting + Auto-Fix) │ └── prettier --write (Formatierung) │ ├── Findet gestagte .json/.md Dateien │ └── prettier --write (Formatierung) │ ▼ Alles OK? → Commit geht durch Fehler? → Commit wird abgelehnt


---

## Einrichtung Schritt fuer Schritt

### 1. Dependencies installieren

```bash
npm install --save-dev husky lint-staged eslint @eslint/js typescript-eslint prettier

2. Husky initialisieren

npx husky init

Das erstellt .husky/pre-commit und fuegt "prepare": "husky" zur package.json hinzu. Das prepare-Script sorgt dafuer, dass der Hook nach jedem npm install automatisch registriert wird — auch bei neuen Team-Mitgliedern.

3. Pre-Commit-Hook setzen

Inhalt von .husky/pre-commit:

npx lint-staged

Kein #!/bin/sh, kein Boilerplate — Husky v9+ braucht das nicht.

4. ESLint Flat Config erstellen

Datei eslint.config.mjs im Root:

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": "warn",
      "@typescript-eslint/explicit-function-return-type": "warn",
      "@typescript-eslint/no-unused-vars": "error",
    },
  },
  {
    ignores: ["build/", "node_modules/", "coverage/"],
  }
);

Hinweis: ESLint 10 unterstuetzt nur Flat Config (eslint.config.mjs). Das alte .eslintrc.json-Format funktioniert nicht mehr.

5. Prettier Config erstellen

Datei .prettierrc im Root:

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

Datei .prettierignore im Root:

build/
node_modules/
coverage/
*.tar.gz

6. lint-staged konfigurieren

Fuer ein einfaches Repository (ein src/-Ordner) reicht die Config direkt in der package.json:

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

Fuer ein Multi-Projekt-Repository (mehrere Unterordner mit eigenen package.json-Dateien) eine dynamische lint-staged.config.mjs:

import { existsSync } from "node:fs";

function isProjectFile(filePath) {
  const dir = filePath.split("/")[0];
  return dir !== filePath && existsSync(`${dir}/package.json`);
}

export default {
  "*.ts": (files) => {
    const projectFiles = files.filter(isProjectFile);
    if (projectFiles.length === 0) return [];
    return [
      `npx eslint --fix ${projectFiles.join(" ")}`,
      `npx prettier --write ${projectFiles.join(" ")}`,
    ];
  },
  "*.{json,md}": (files) => {
    const projectFiles = files.filter(isProjectFile);
    if (projectFiles.length === 0) return [];
    return [`npx prettier --write ${projectFiles.join(" ")}`];
  },
};

7. .gitignore pruefen

Sicherstellen, dass node_modules/ ignoriert wird. package-lock.json sollte nicht ignoriert werden — Lock-Files gehoeren committed.


Fuer neue Team-Mitglieder

Nach dem Klonen des Repos:

npm install

Das ist alles. Das prepare-Script registriert den Git-Hook automatisch.


Haeufige Fragen

Der Commit schlaegt fehl — was tun?

  1. Fehlermeldung lesen (ESLint zeigt Datei + Zeile)
  2. Fehler beheben
  3. git add <datei> (erneut stagen)
  4. git commit (nochmal committen)

Kann ich den Hook umgehen?

Ja, mit git commit --no-verify. Sollte aber die Ausnahme sein — der Hook schuetzt die Code-Qualitaet.

Warum nicht ESLint + Prettier auf dem gesamten Codebase?

lint-staged prueft nur gestagte Dateien. Das ist schnell (Sekunden statt Minuten) und verhindert, dass ein Entwickler existierende Probleme in Dateien fixen muss, die er gar nicht angefasst hat.

ESLint und Prettier — widersprechen die sich nicht?

Nein. ESLint prueft Logik und Best Practices (ungenutzte Variablen, fehlende Typen etc.). Prettier kuemmert sich nur um Formatierung (Einrueckung, Zeilenlaenge etc.). Reihenfolge: erst ESLint (--fix), dann Prettier (--write).


Optionale Erweiterungen

Tool Zweck Wann sinnvoll
commitlint Commit-Messages pruefen (Conventional Commits) Wenn Changelog automatisch generiert werden soll
tsc --noEmit TypeScript-Typfehler vor dem Commit Wenn strikte Typsicherheit gewuenscht ist (erhoet die Commit-Dauer)
Jest / Vitest Tests als pre-push Hook Tests vor dem Push, nicht vor jedem Commit (zu langsam)

Vergleich: Python vs. TypeScript

Fuer Teams die beide Oekosysteme nutzen:

Aspekt Python TypeScript
Hook-Framework pre-commit (Python-basiert) Husky (npm-basiert)
Staged-File-Filter Built-in bei pre-commit lint-staged (separates Tool)
Linter Ruff (ruff check --fix) ESLint (eslint --fix)
Formatter Ruff (ruff format) Prettier (prettier --write)
Hook-Registrierung uv run pre-commit install npm install (via prepare-Script)
Config-Datei .pre-commit-config.yaml package.json oder lint-staged.config.mjs