typescript-type-design
Implement and test advanced TypeScript types and inference; not diff review or runtime validation.
SKILL.mdclaude/skills/typescript-type-design/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-designto decide the consumer-facing contract before implementation,code-reviewto inspect a changed implementation without edits, andzodto implement Zod runtime schemas. - Use
vet-dependencyto select a validation library anddeprecation-and-migrationfor 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
- 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.
- Use
satisfiesfor 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. - 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. - 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.
- Prefer
unknownat untrusted boundaries. Anas, non-null assertion, user-defined predicate, oranydoes not prove a value's shape. If an assertion is unavoidable inside a checked abstraction, isolate and justify the invariant; never useas anyto make the promised contract appear to compile. - 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.