Claude
Skills
Sign in
Back

typescript

Included with Lifetime
$97 forever

TypeScript type system, strict mode, and TS-specific patterns beyond JavaScript fundamentals. Invoke whenever task involves any interaction with TypeScript code — writing, reviewing, refactoring, debugging .ts/.tsx files, type definitions, generics, narrowing, tsconfig, or type-level programming.

Productivity

What this skill does


# TypeScript

<prerequisite>
This skill extends the JavaScript skill. You must load `javascript` first — naming,
ternary operator rules, async patterns, and module conventions are defined there and
not duplicated here.
</prerequisite>

**Types encode intent. Let the compiler prove the rest.**

TypeScript's value is in catching bugs at compile time. Write types that express your domain; let inference handle the
obvious. Never fight the type system — if you need `as` or `any`, the types are wrong.

## References

| Topic                                              | Reference                                           | Contents                                                                           |
| -------------------------------------------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Generics, utility types, type-level programming    | [`${CLAUDE_SKILL_DIR}/references/generics.md`]      | Utility type tables, conditional/mapped type examples, infer, template literals    |
| Narrowing, type guards, discriminated unions       | [`${CLAUDE_SKILL_DIR}/references/narrowing.md`]     | typeof/instanceof/in examples, exhaustive switch, type predicates, assertion fns   |
| tsconfig options, module resolution, project setup | [`${CLAUDE_SKILL_DIR}/references/configuration.md`] | Base/strict/module configs, library setup, compiler directives, project structure  |
| Branded types, overloads, class patterns, enums    | [`${CLAUDE_SKILL_DIR}/references/patterns.md`]      | Interface vs type examples, assertion patterns, enum anti-patterns, callback types |

## Type Safety

- **`strict: true` always.** No exceptions. It enables `strictNullChecks`, `noImplicitAny`, `strictFunctionTypes`, and
  other critical checks.
- **`unknown` over `any`.** Use `unknown` and narrow with type guards. `any` disables type checking entirely. Reserve
  `any` for migration or test mocks only — document why.
- **No non-null assertions (`!`) without justification.** Prefer narrowing. If `!` is truly needed, add a comment
  explaining why the value cannot be null.
- **No type assertions (`as`) for object literals.** Use type annotations (`: Foo`) instead — assertions hide
  missing/extra property errors.

### `unknown` vs `any` Decision

- **Value from external source (API, JSON.parse, user input)** → `unknown`
- **Function accepts anything, passes through without touching** → `unknown`
- **Migrating JS to TS incrementally** → `any` (temporary, with comment)
- **Test mock that intentionally bypasses type checking** → `any` (with comment)

### The `{}` Type

`{}` means "any non-nullish value" — almost never what you want.

- **`unknown`** → Everything (null, undefined, primitives, objects)
- **`object`** → Non-primitive, non-null values
- **`{}`** → Any non-nullish value (primitives included)
- **`Record<string, unknown>`** → Objects with string keys

Prefer `unknown` for opaque values, `Record<string, unknown>` for dict-like objects, `object` when you need "any
non-primitive".

## Type Annotations

- **Omit trivially inferred types.** Don't annotate `const x: number = 5` or `const s: string = "hello"`. The compiler
  infers these correctly.
- **Annotate complex return types.** When inference produces opaque or wide types, annotate explicitly for readability.
- **Annotate function signatures at API boundaries.** Exported functions and public methods should have explicit
  parameter and return types.
- **Use `import type` for type-only imports.** Enforced by `verbatimModuleSyntax`. Use `export type` for type re-exports
  — required for `isolatedModules`.
- **Annotate for precision with structural types.** Annotate at declaration so errors appear where the bug is, not at
  distant call sites.

## Interfaces and Types

- **`interface` for object shapes.** Better error messages, IDE support, and performance.
- **`type` for everything else** — unions, intersections, tuples, function types, mapped/conditional types.
- **Decision rule:** Object shape with known properties? `interface`. Everything else? `type`. Pick one pattern per kind
  and stay consistent within a project.
- **No empty interfaces.** Use a branded type or discriminated union as a marker.
- **No `namespace`.** Use ES modules. `namespace` is legacy.
- **No wrapper types.** `string` not `String`, `number` not `Number`.
- **Use interfaces for data shapes, not classes.** A class used purely as a data shape adds unnecessary overhead.

## Null Handling

- **Prefer optional `?` over `| undefined`** for fields and parameters. `| undefined` forces callers to pass `undefined`
  explicitly.
- **Don't include `null`/`undefined` in type aliases.** Keep nullability at the use site:
  `function getUser(): User | null` not `type MaybeUser = User | null`.
- **Null narrowing:** `!= null` checks both null and undefined (the one valid `==` use). `?.` for optional access. `??`
  for defaults.

## Generics

- **Name type parameters descriptively** when meaning is non-obvious. `T` is fine for single-parameter generics; use
  `TKey`, `TValue`, `TItem` for multiple parameters.
- **Constrain generics** with `extends` when possible. `<T extends string>` is better than `<T>` if `T` must be a
  string.
- **Keep generic constraints tight** — `<T extends Record<string, unknown>>` is better than `<T extends object>` when
  you need string keys.
- **Don't add unused type parameters.** Every generic must appear in the signature.
- **Avoid return-type-only generics.** If a generic appears only in the return type, it cannot be inferred and forces
  callers to guess.
- **Let inference work.** Don't specify type arguments when the compiler can infer them: `identity("hello")` not
  `identity<string>("hello")`.
- **Use type parameters in constraints:** `<T, K extends keyof T>` to relate parameters.
- **Generic parameter defaults:** `interface Container<T, U = T[]>` — omitted type args fall back to the default.
- **`NoInfer<T>`** (TS 5.4+) prevents a parameter from being an inference site — use when a parameter should be
  constrained by other params, not drive inference.

### Utility Types

Prefer built-in utility types over hand-rolling equivalents. Key types: `Partial`, `Pick`, `Omit`, `Record`, `Exclude`,
`Extract`, `ReturnType`, `Parameters`, `Awaited`, `NoInfer`. Use explicit interfaces when the type represents a distinct
domain concept. See `${CLAUDE_SKILL_DIR}/references/generics.md` for the full catalog and usage guidance.

Conditional types (`T extends U ? X : Y`), mapped types (`{ [P in keyof T]: ... }`), and template literal types
(`` `${T}Changed` ``) are advanced tools — use for library code and framework types. See
`${CLAUDE_SKILL_DIR}/references/generics.md` for distributive behavior, `infer`, modifier removal, and key remapping.

### Complexity Budget

- **Simple** (`interface`, `type` alias, union) → Always — default choice
- **Moderate** (`Partial`, `Pick`, `Omit`, `Record`) → Well-known transformations
- **Advanced** (Conditional, mapped, template literal) → Library code, framework types
- **Expert** (Recursive types, complex `infer` chains) → Rarely — last resort

Stay at the lowest tier that solves your problem. If you can't explain what a type does in one sentence, it's too
complex — split it, simplify it, or use explicit interfaces.

## Narrowing

- **Prefer discriminated unions** for variant types. Add a `kind` or `type` literal field to each variant.
- **Use exhaustive switches.** Add `default: { const _exhaustive: never = value; return _exhaustive; }` to catch
  unhandled variants at compile time.
- **Type predicates for reusable guards:** `function isFish(pet: Animal): pet is Fish`. Use when filtering arrays or in
  multiple call sites.
- **Assertion functions:** `function assertIsError(value: unknown): asserts value is Error` — use for validation at
  boundaries.
- **`typeof`, `instanceof`, `in`** — use JavaScript narrowing cons

Related in Productivity