typescript-type-design

Implement and test advanced TypeScript types and inference; not diff review or runtime validation.

SKILL.md

GitHub
<!-- GENERATED BY generate_skill_wrappers.py; DO NOT EDIT MANUALLY. -->

Generated Claude Code skill — do not edit manually

This complete skill and its bundled resources are generated from agent-plugins/skills/typescript-type-design/SKILL.md. Manual changes in this directory will be overwritten the next time the generator runs. Edit the canonical skill instead.

TypeScript Type Design

Build the smallest type-level mechanism that expresses a required caller contract. Selected topics adapt wshobson's typescript-advanced-types, under the bundled LICENSE.wshobson-agents. Examples here are rewritten.

Route precisely

  • Use to implement or repair generic inference, conditional or mapped types, discriminated unions, branded domain types, declaration utilities, or compile-time consumer constraints.
  • Use api-and-interface-design to decide the consumer-facing contract before implementation, code-review to inspect a changed implementation without edits, and zod to implement Zod runtime schemas.
  • Use vet-dependency to select a validation library and deprecation-and-migration for a breaking public-contract rollout. Do not introduce advanced types merely because a project uses TypeScript.

Establish the actual environment

Read repository instructions, owning package, compiler and supported consumer versions, effective tsconfig/project references, module/exports configuration, local type-test convention, and the relevant callers. Preserve unrelated work. Do not install dependencies, switch package managers, enable strictness flags, or replace module resolution without that change being in scope. In particular, bundler resolution is not a universal Node configuration.

Write representative accepted and rejected calls, the intended inference, and runtime assumptions before choosing the mechanism. Static types do not validate JSON or grant authorization. A brand represents an invariant only if its construction boundary establishes that invariant.

Implement proportionately

  1. Prefer ordinary inferred types and simple unions first. Use a discriminant to model mutually exclusive states when the domain has them; preserve exhaustive handling when variants change.
  2. Use satisfies for assignability checks that should preserve useful inference; it does not perform runtime validation or guarantee all property values remain literals. Use const assertions deliberately for literal/readonly inference.
  3. For conditional types, state whether union distribution is intended. Handle never, unknown, empty inputs, optional members, readonly arrays/tuples, and overloads only where the contract requires them. Do not promise that one utility models every TypeScript type.
  4. For generic functions, check inference at real call sites, not just explicit type arguments. Ensure a union-valued key cannot decouple a payload from its discriminant. Keep overloads and emitted declarations compatible with supported consumers.
  5. Prefer unknown at untrusted boundaries. An as, non-null assertion, user-defined predicate, or any does not prove a value's shape. If an assertion is unavoidable inside a checked abstraction, isolate and justify the invariant; never use as any to make the promised contract appear to compile.
  6. Bound recursive utilities and keep compiler cost proportionate. A type that exhausts compiler instantiation limits is not a usable contract. Do not build speculative generic frameworks or replace established error handling with Result solely as a style choice.

Verify the type contract

Use the owning project's configured type-check command and actual compiler version. Runtime tests and transpile-only runners do not type-check. See references/type-contracts.md for independent positive and negative cases.

Require positive assertions with an enforcing constraint such as Expect<T extends true>; a type alias that merely evaluates to false cannot fail the build. Use the project's existing type-test tool or narrowly placed @ts-expect-error directives for rejected calls. Remove each suppression in an isolated control and verify the expected diagnostic appears. Check that an unused directive itself fails, rather than silently accepting a now-permitted call.

For public declarations, check representative supported consumers and emitted declarations as relevant. Run runtime tests separately for behavior, validation, and serialization. Do not claim downstream compatibility from one local compile.

Report

Return the contract, changed type/consumer boundary, accepted and rejected cases, compiler/version/configuration, observed diagnostics and controls, runtime checks, and limits. Mark missing compilers, skipped checks, or untested consumer versions explicitly. Do not claim type safety from a successful execution-only test.