P PasteCode
Rule

AI Coding Rules for TypeScript Strict Projects

AGENTS.md rules for TypeScript strict-mode projects that eliminate any types, enforce narrowing patterns, and prevent agents from compiling-but-wrong code.

CursorClaude CodeCodexWindsurf TypeScriptNext.js
.md .json Updated Jun 8, 2026

Drop this in your repo root as AGENTS.md. TypeScript strict mode is only as useful as the rules that prevent agents from defeating it with any casts and @ts-ignore comments.

AGENTS.md

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.

Why these rules

  • No as T without a comment is the most important rule after banning any. Type assertions are the primary way agents “fix” TypeScript errors without actually fixing them — the code compiles but the runtime type guarantee is gone. Requiring a written justification forces agents to reason about whether the assertion is actually safe.
  • Validate external data at the boundary prevents the widest class of runtime type errors in TypeScript applications. Agents that see a typed API response often trust the type annotation without checking whether it was validated at fetch time, producing apps where the TypeScript types are lies that compile cleanly but crash unpredictably.

Good fit

  • Production TypeScript codebases with strict: true where type safety is a first-class quality requirement — especially those that handle user data, financial transactions, or external API integrations.

Not a fit

  • Rapid prototyping or scripts where strict type safety adds overhead without benefit — use strict: false and a lighter rule set for throwaway code.