All TypeScript templates

TypeScript Strict Rules

Strict mode, no any, narrow types, exhaustive checks, branded types.

DevZone Tools3,480 copiesUpdated Apr 20, 2026TypeScript
# CLAUDE.md — TypeScript Strict Rules

## tsconfig

- `strict: true` is the floor. Add the rest of the strictness flags:
  ```json
  {
    "compilerOptions": {
      "strict": true,
      "noUncheckedIndexedAccess": true,
      "exactOptionalPropertyTypes": true,
      "noImplicitOverride": true,
      "noFallthroughCasesInSwitch": true,
      "useUnknownInCatchVariables": true,
      "verbatimModuleSyntax": true
    }
  }
  ```
- ESLint `@typescript-eslint/no-explicit-any` is `error`, not `warn`.
- `noEmitOnError: true` so a compile error fails the build.

## Anti-`any`

- `any` is banned. Use `unknown` and narrow.
- Stuck on a third-party type? Write a `.d.ts` declaration that's tighter than the upstream.
- `// @ts-expect-error` over `// @ts-ignore` — it errors when the issue is fixed, telling you to remove it.

## Type narrowing

- Use type predicates (`x is Foo`) for custom narrows. They're functions returning a typed boolean.
- Discriminated unions with a literal `kind` / `type` tag for state machines and result types:
  ```ts
  type Result<T> = { ok: true; value: T } | { ok: false; error: string }
  ```
- `switch` on the discriminator with `default: assertNever(x)` for exhaustiveness.

## `as` casts

- `as` is a sharp tool. Allow only:
  - Narrowing `unknown` after a runtime check
  - `const` assertions: `as const`
  - Casting an empty array to a specific tuple type
- Forbidden: `as Foo`, `as unknown as Bar`. If you need it, you're missing a runtime check or a type predicate.

## Branded types

- Use branded types for IDs and other primitives that look the same but aren't:
  ```ts
  type UserId = string & { readonly __brand: "UserId" }
  ```
- Construct via a factory function that runs the validation. Don't cast.

## Generics

- Single-letter generics for simple cases (`T`, `K`, `V`). Descriptive names for complex ones (`TUser`, `TKey`).
- Constrain generics with `extends` — unbounded `T` is rarely what you want.
- Avoid generics that exist only to "remember" a type. If the type is the same in and out, you don't need a generic.

## Errors

- Throw `Error` subclasses with a `name`. Don't throw strings.
- `try/catch` with `useUnknownInCatchVariables` forces you to narrow before reading the error. Use `if (err instanceof MyError)`.
- Don't return errors via union types from unrelated functions. Pick a layer where Result types make sense and stay there.

## Don't

- Don't use `Object`, `Function`, `{}` as types. They mean "anything".
- Don't write `Array<X>` and `X[]` mixed in the same file. Pick one.
- Don't use TypeScript enums. Use string-literal unions or `as const` objects.
- Don't write barrel files that re-export everything — they break tree-shaking.

Other TypeScript templates