{
  "id": "ai-rules-for-typescript-strict-projects",
  "type": "rules",
  "category": "rules",
  "locale": "de",
  "url": "/de/rules/ai-rules-for-typescript-strict-projects",
  "title": "KI-Codierungsregeln für TypeScript-Strict-Projekte",
  "description": "AGENTS.md-Regeln für TypeScript Strict-Mode-Projekte, die jegliche Typen eliminieren, Narrowing-Muster erzwingen und verhindern, dass Agents Code kompilieren, der zwar funktioniert, aber falsch ist.",
  "tools": [
    "Cursor",
    "Claude Code",
    "Codex",
    "Windsurf"
  ],
  "stack": [
    "TypeScript",
    "Next.js"
  ],
  "tags": [
    "agents-md",
    "typescript",
    "conventions",
    "security"
  ],
  "difficulty": null,
  "updated": "2026-06-08",
  "markdown": "Legen Sie dies als `AGENTS.md` im Stammverzeichnis Ihres Repos ab. TypeScript Strict Mode ist nur so nützlich wie die Regeln, die verhindern, dass Agents ihn mit `any`-Casts und `@ts-ignore`-Kommentaren umgehen.\n\n## AGENTS.md\n\n```md title=\"AGENTS.md\"\n# Project Rules — TypeScript Strict\n\n## TypeScript configuration\n- `strict: true` is set in `tsconfig.json`. This enables `noImplicitAny`,\n  `strictNullChecks`, `strictFunctionTypes`, `strictBindCallApply`,\n  `strictPropertyInitialization`, and `noImplicitThis`. Do not disable any of these.\n- `noUncheckedIndexedAccess: true` is enabled. Array indexing returns `T | undefined`.\n  Always check array access results before using them.\n- `exactOptionalPropertyTypes: true` is enabled. Do not assign `undefined` to an\n  optional property — omit the property instead.\n\n## Hard rules — no exceptions\n- NEVER use `any`. Use `unknown` for values of uncertain type and narrow them\n  before use. The single exception is third-party library types that are themselves\n  typed as `any` — wrap and re-export with a proper type.\n- NEVER use `as T` type assertions unless you add a comment explaining why the\n  compiler cannot infer the type and why the assertion is safe. Prefer type guards.\n- NEVER use `@ts-ignore` or `@ts-expect-error` without a comment on the same line\n  explaining the exact reason. If you find yourself using these, refactor instead.\n- NEVER use non-null assertion (`!`) on values that could genuinely be null/undefined\n  at runtime. Write an explicit check or use optional chaining (`?.`).\n- NEVER widen a type unnecessarily. If a function returns `string`, type it as\n  `string` — not `string | undefined` just to avoid a null check.\n\n## Type design conventions\n- Model domain errors with discriminated unions, not thrown errors or `null`.\n  Return `{ ok: true; value: T } | { ok: false; error: string }` from fallible\n  operations instead of relying on catch at the call site.\n- Prefer `type` aliases for unions and intersections; use `interface` for object\n  shapes that may be extended. Be consistent within a file.\n- Generic constraints should be as narrow as possible: `T extends string` instead of\n  `T extends unknown` when you only use string operations on `T`.\n- Export only what callers need. Keep internal implementation types unexported unless\n  there is an explicit reason to expose them.\n\n## Narrowing and runtime validation\n- All external data (API responses, form input, `JSON.parse` output, URL params) must\n  be validated at the boundary with Zod or a type guard before being used as a typed\n  value. Never cast external data with `as MyType` without validation.\n- Use `satisfies` to validate object literals against a type without widening:\n  `const config = { ... } satisfies Config` instead of `const config: Config = { ... }`\n  when you need to preserve literal types.\n- Exhaustiveness checks in `switch` statements: add a `default: assertNever(x)` arm\n  where `assertNever` is `(x: never) => never` — this catches unhandled union members\n  at compile time when the union is extended.\n\n## Definition of done\n- `tsc --noEmit` passes with zero errors.\n- `grep -r 'as any\\|: any\\|@ts-ignore\\|@ts-expect-error' src/` returns zero results\n  (or every hit has an approved justification comment).\n- ESLint with `@typescript-eslint/no-explicit-any` and `@typescript-eslint/no-unsafe-*`\n  rules enabled passes.\n- No `!` non-null assertions on values that come from external data or optional fields.\n```\n\n## Warum diese Regeln\n\n- **Kein `as T` ohne Kommentar** ist die wichtigste Regel nach dem Verbot von `any`. Typbehauptungen sind die primäre Methode, mit der Agents TypeScript-Fehler „beheben“, ohne sie tatsächlich zu beheben — der Code kompiliert, aber die Laufzeit-Typgarantie ist verloren. Das Erzwingen einer schriftlichen Begründung zwingt Agents dazu, zu überlegen, ob die Behauptung tatsächlich sicher ist.\n- **Validieren Sie externe Daten an der Grenze** verhindert die häufigste Klasse von Laufzeit-Typfehlern in TypeScript-Anwendungen. Agents, die eine typisierte API-Antwort sehen, vertrauen oft der Typannotation, ohne zu prüfen, ob sie beim Abruf validiert wurde. Das führt zu Apps, bei denen die TypeScript-Typen Lügen sind, die sauber kompilieren, aber unvorhersehbar abstürzen.\n\n## Geeignet für\n\n- Produktions-TypeScript-Codebasen mit `strict: true`, bei denen Typsicherheit eine erstklassige Qualitätsanforderung ist — insbesondere solche, die Benutzerdaten, Finanztransaktionen oder externe API-Integrationen verarbeiten.\n\n## Nicht geeignet für\n\n- Schnelles Prototyping oder Skripte, bei denen strenge Typsicherheit mehr Aufwand als Nutzen bringt — verwenden Sie `strict: false` und ein leichteres Regelwerk für Wegwerfcode."
}