# Typescript Engineer

> Resolve TypeScript errors, eliminate `any`, and design complex types (generics, conditional, mapped, template literal, branded/opaque). Use for type-inference problems, `infer` / `extends` questions, utility types (`Partial`, `Record`, `ReturnType`, `Awaited`, `NoInfer`), `satisfies`, function overloads, declaration merging, and strict-mode refactors.

- Skill: `johnie/typescript-engineer` (Agent Skill, multi-file: 19 files)
- Install (CLI): `npx skillmds@latest add johnie/typescript-engineer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/johnie/typescript-engineer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: johnie (https://skillmd.com/u/johnie)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/johnie/typescript-engineer

---


# TypeScript Engineer

Type-level design, compiler-error diagnosis, and strict-safety refactoring. This skill routes the user's intent to a set of focused rule files in `references/`; don't try to answer from SKILL.md alone on anything non-trivial.

Reference files live in `${CLAUDE_SKILL_DIR}/references/`.

## When NOT to use

- Runtime validation — use Zod / io-ts / Valibot (separate concern; types won't validate unknown input at the boundary).
- Refactors that change runtime behavior — this skill preserves behavior. If the change is behavioral, use a refactoring / testing skill.
- Build tooling issues (`tsc` not found, wrong `tsconfig` paths, module resolution not finding files) — that's config, not type-level design.
- JavaScript-only questions where types aren't involved.

## Decision tree

Identify the user's goal first, then load the matching rule file on demand.

```text
1. "Something doesn't compile / tsc is red"
   → start at references/error-diagnosis.md
   → then the rule file that matches the error category

2. "Design a type / API for X"
   → references/generics-basics.md (always the foundation)
   → then conditional-types.md / mapped-types.md / template-literal-types.md
     depending on whether you need branching, per-key transforms, or string ops

3. "Remove any / tighten types in this code"
   → references/type-narrowing.md (for input validation)
   → references/utility-types.md (for structural transforms)
   → references/generics-basics.md (when a function/class needs to be generic)

4. "Explain / teach concept X"
   → match X in the routing table below
```

## Routing table

Match keywords in the user's request to load the right rule file.

| Keyword / topic | Rule file |
| --- | --- |
| `as const`, `typeof`, `satisfies`, enum alternative, derive types from values | [as-const-typeof.md](references/as-const-typeof.md) |
| array element type, `[number]` index | [array-index-access.md](references/array-index-access.md) |
| `Partial`, `Record`, `Omit`, `Pick`, `ReturnType`, `Parameters`, `Awaited`, `NoInfer`, utility type | [utility-types.md](references/utility-types.md) |
| generic, constraint, `extends`, type parameter | [generics-basics.md](references/generics-basics.md) |
| builder pattern, chainable, fluent API | [builder-pattern.md](references/builder-pattern.md) |
| deep inference, `const` type parameter, preserve literal types, `F.Narrow` in old code | [deep-inference.md](references/deep-inference.md) |
| conditional type, `extends ? :`, distribute | [conditional-types.md](references/conditional-types.md) |
| `infer`, extract inner type | [infer-keyword.md](references/infer-keyword.md) |
| template literal type, string manipulation at type level | [template-literal-types.md](references/template-literal-types.md) |
| mapped type, `in keyof`, transform properties | [mapped-types.md](references/mapped-types.md) |
| brand type, opaque type, nominal typing, validated ID | [opaque-types.md](references/opaque-types.md) |
| narrowing, `typeof`, `instanceof`, `in`, discriminated union, type guard, `is` | [type-narrowing.md](references/type-narrowing.md) |
| assertion function, `asserts value is`, validate-and-throw | [assertion-functions.md](references/assertion-functions.md) |
| overload, multiple signatures | [function-overloads.md](references/function-overloads.md) |
| type test, prove a type, assert a type, `Expect`, `Equal`, `@ts-expect-error` | [type-testing.md](references/type-testing.md) |
| type error, diagnostic, `ts(…)`, "not assignable" | [error-diagnosis.md](references/error-diagnosis.md) |
| TS version, "which version added", 5.5 / 5.9 / 6 / 7, `erasableSyntaxOnly`, `stableTypeOrdering`, native compiler, no compiler API, upgrade broke my build | [typescript-versions.md](references/typescript-versions.md) |

## Working style

- **Check the version.** Read `typescript` in `package.json` (or run `npx tsc --version`) before recommending anything version-gated. TypeScript 5.5 infers type predicates and 5.8 can ban `enum` outright, so the same advice is right or wrong depending on the target. [typescript-versions.md](references/typescript-versions.md) lists what changed.
- **Reproduce first.** Run `tsc --noEmit` on the user's code before proposing a fix so you're reasoning about the real error, not a guess. Since 7.0 the compiler is a native binary and whole-project checks are fast — prefer a real run over reasoning from a snippet.
- **Simplest type that works.** Don't reach for conditional/mapped/template-literal machinery when a plain generic or utility type would do. Complexity has a cost to everyone who reads the code later.
- **Validate type-level code.** Use the `Expect<Equal<A, B>>` pattern (or similar) to prove the types are what you claim — see [type-testing.md](references/type-testing.md). Types that compile but are wrong are worse than runtime bugs — they silently lie.
- **Explain why the type works.** Dense types are hard to read; a one-line comment naming the technique (`// distributive conditional over UnionKey`) pays for itself.

## One snippet per category

These are smell-tests — read them, then jump to the reference file for the full pattern.

### Eliminate `any` with a generic

```ts
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
// getProperty({ name: "Alice" }, "name") → inferred as string
```

See [generics-basics.md](references/generics-basics.md).

### Narrow an unknown response at the boundary

```ts
function isUser(value: unknown): value is { id: number; name: string } {
  return (
    typeof value === "object" &&
    value !== null &&
    "id" in value &&
    "name" in value
  );
}
```

Two things to flag when you write one of these. `in` proves the keys exist but says nothing about their types, so the annotation is a promise the body doesn't keep — if the shape arrives over the network, validate it with Zod/Valibot instead. And on TS 5.5+ a guard like this often doesn't need the annotation at all; see [typescript-versions.md](references/typescript-versions.md).

See [type-narrowing.md](references/type-narrowing.md) and [assertion-functions.md](references/assertion-functions.md).

### Preserve literals while enforcing shape

```ts
const palette = {
  red: [255, 0, 0],
  green: [0, 255, 0],
} as const satisfies Record<string, readonly [number, number, number]>;
// palette.red → readonly [255, 0, 0]
```

See [as-const-typeof.md](references/as-const-typeof.md).

## Reference map

Core patterns — [as-const-typeof](references/as-const-typeof.md) · [array-index-access](references/array-index-access.md) · [utility-types](references/utility-types.md)

Generics — [generics-basics](references/generics-basics.md) · [builder-pattern](references/builder-pattern.md) · [deep-inference](references/deep-inference.md)

Type-level programming — [conditional-types](references/conditional-types.md) · [infer-keyword](references/infer-keyword.md) · [template-literal-types](references/template-literal-types.md) · [mapped-types](references/mapped-types.md)

Safety — [opaque-types](references/opaque-types.md) · [type-narrowing](references/type-narrowing.md) · [assertion-functions](references/assertion-functions.md) · [function-overloads](references/function-overloads.md)

Debugging — [error-diagnosis](references/error-diagnosis.md) · [type-testing](references/type-testing.md) · [typescript-versions](references/typescript-versions.md)

