# Règles de codage IA pour les projets TypeScript en mode strict

> Règles AGENTS.md pour les projets TypeScript en mode strict qui éliminent les types `any`, imposent des motifs de narrowing et empêchent les agents de compiler du code erroné.

**Type:** Rule  
**Tools:** Cursor, Claude Code, Codex, Windsurf  
**Stack:** TypeScript, Next.js  
**Updated:** 2026-06-08

---

Placez ceci à la racine de votre dépôt sous le nom `AGENTS.md`. Le mode strict de TypeScript n'est utile que dans la mesure où des règles empêchent les agents de le contourner avec des casts `any` et des commentaires `@ts-ignore`.

## AGENTS.md

```md title="AGENTS.md"
# Project Rules — TypeScript Strict

## TypeScript configuration
- `strict: true` is set in `tsconfig.json`. This enables `noImplicitAny`,
  `strictNullChecks`, `strictFunctionTypes`, `strictBindCallApply`,
  `strictPropertyInitialization`, and `noImplicitThis`. Do not disable any of these.
- `noUncheckedIndexedAccess: true` is enabled. Array indexing returns `T | undefined`.
  Always check array access results before using them.
- `exactOptionalPropertyTypes: true` is enabled. Do not assign `undefined` to an
  optional property — omit the property instead.

## Hard rules — no exceptions
- NEVER use `any`. Use `unknown` for values of uncertain type and narrow them
  before use. The single exception is third-party library types that are themselves
  typed as `any` — wrap and re-export with a proper type.
- NEVER use `as T` type assertions unless you add a comment explaining why the
  compiler cannot infer the type and why the assertion is safe. Prefer type guards.
- NEVER use `@ts-ignore` or `@ts-expect-error` without a comment on the same line
  explaining the exact reason. If you find yourself using these, refactor instead.
- NEVER use non-null assertion (`!`) on values that could genuinely be null/undefined
  at runtime. Write an explicit check or use optional chaining (`?.`).
- NEVER widen a type unnecessarily. If a function returns `string`, type it as
  `string` — not `string | undefined` just to avoid a null check.

## Type design conventions
- Model domain errors with discriminated unions, not thrown errors or `null`.
  Return `{ ok: true; value: T } | { ok: false; error: string }` from fallible
  operations instead of relying on catch at the call site.
- Prefer `type` aliases for unions and intersections; use `interface` for object
  shapes that may be extended. Be consistent within a file.
- Generic constraints should be as narrow as possible: `T extends string` instead of
  `T extends unknown` when you only use string operations on `T`.
- Export only what callers need. Keep internal implementation types unexported unless
  there is an explicit reason to expose them.

## Narrowing and runtime validation
- All external data (API responses, form input, `JSON.parse` output, URL params) must
  be validated at the boundary with Zod or a type guard before being used as a typed
  value. Never cast external data with `as MyType` without validation.
- Use `satisfies` to validate object literals against a type without widening:
  `const config = { ... } satisfies Config` instead of `const config: Config = { ... }`
  when you need to preserve literal types.
- Exhaustiveness checks in `switch` statements: add a `default: assertNever(x)` arm
  where `assertNever` is `(x: never) => never` — this catches unhandled union members
  at compile time when the union is extended.

## Definition of done
- `tsc --noEmit` passes with zero errors.
- `grep -r 'as any\|: any\|@ts-ignore\|@ts-expect-error' src/` returns zero results
  (or every hit has an approved justification comment).
- ESLint with `@typescript-eslint/no-explicit-any` and `@typescript-eslint/no-unsafe-*`
  rules enabled passes.
- No `!` non-null assertions on values that come from external data or optional fields.
```

## Pourquoi ces règles

- **Pas de `as T` sans commentaire** est la règle la plus importante après l'interdiction de `any`. Les assertions de type sont le principal moyen pour les agents de « corriger » les erreurs TypeScript sans les résoudre réellement — le code compile mais la garantie de type à l'exécution disparaît. Exiger une justification écrite oblige les agents à réfléchir à la sécurité réelle de l'assertion.
- **Valider les données externes à la frontière** évite la plus grande classe d'erreurs de type à l'exécution dans les applications TypeScript. Les agents qui voient une réponse API typée font souvent confiance à l'annotation de type sans vérifier si elle a été validée au moment du fetch, produisant des applications où les types TypeScript sont des mensonges qui compilent proprement mais plantent de manière imprévisible.

## Bonnes correspondances

- Bases de code TypeScript en production avec `strict: true` où la sécurité des types est une exigence de qualité de premier ordre — en particulier celles qui traitent des données utilisateur, des transactions financières ou des intégrations d'API externes.

## Pas adapté

- Prototypage rapide ou scripts où la sécurité stricte des types ajoute une surcharge sans avantage — utilisez `strict: false` et un ensemble de règles plus léger pour du code jetable.