typescript-strict

Enforces strict TypeScript patterns using discriminated unions, branded types, and schema-first boundary validation.

Updated May 18, 2024
One-click install
npx skills add https://github.com/joshhornby/dotfiles --skill typescript-strict-joshhornby
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: typescript-strict
Source: https://github.com/joshhornby/dotfiles/tree/main/.claude/skills/typescript-strict
Command: npx skills add https://github.com/joshhornby/dotfiles --skill typescript-strict-joshhornby

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? TypeScript codebases often allow invalid states to be represented through loose boolean flags, optional fields, and unchecked any types, leading to runtime bugs that the compiler could have caught. This Skill guides you to design types so invalid states cannot be written down, and to validate untrusted data only at trust boundaries. ## Core Features & Use Cases - Impossible-state elimination: Model state as discriminated unions with exhaustive never-default switches so adding a variant surfaces every affected call site as a compile error. - Branded types and smart constructors: Constrain primitives like UserId or PaymentMinorUnits behind validating constructors, keeping type assertions confined to one justified location. - Schema-first trust boundaries: Validate HTTP, queue, file, and third-party data with Standard Schema libraries such as Zod, Valibot, or ArkType, then translate wire shapes into owned domain types. - Strict compiler configuration: Apply strict, noUncheckedIndexedAccess, exactOptionalPropertyTypes, and related flags with guidance on when each is justified. - Use Case: When reviewing a booking model with four status booleans and three optional payloads, refactor it into a four-variant discriminated union so reference cannot be absent on a confirmed booking and no defensive guards are needed. ## Quick Start Ask the AI to review your TypeScript types and refactor boolean-and-optional state bags into discriminated unions with branded primitives and boundary validation.

Frequently Asked Questions about typescript-strict

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I model state with discriminated unions in TypeScript?

Define a type where each variant carries a literal tag field plus only the data valid in that state, such as `{ status: 'loggedIn'; username: string }`. Switch on the tag with a `never` default so the compiler errors on any unhandled variant.

When should I use type vs interface in TypeScript?

Use `type` for unions, tuples, mapped types, and closed aliases since they cannot be reopened by declaration merging. Use `interface` for extendable object contracts that work with `implements` and deliberate extension points.

What are branded types in TypeScript and when should I use them?

Branded types intersect a primitive with a unique symbol, like `string & { readonly brand: unique symbol }`, so raw values cannot be passed where validated ones are required. Use them when only some strings or numbers are valid, with one validating constructor holding the single justified type assertion.

Does Zod validation belong on internal TypeScript types?

No, runtime schemas are only required where untrusted data crosses a boundary, such as HTTP, queue, file, or third-party input. Internal types, Result types, and component props rely on the compiler, smart constructors, or domain unions instead.

Which strict tsconfig flags should I enable beyond strict mode?

Enable `noUnusedLocals`, `noUnusedParameters`, `noImplicitReturns`, and `noFallthroughCasesInSwitch` as project checks. Assess `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, and `noPropertyAccessFromIndexSignature` against your codebase for deeper safety.

When is a discriminated union not the right choice?

Skip unions when no invalid combinations are removed, such as independent optionals in a PATCH payload, options bags, or config files. Also keep external wire shapes as-is at the edge and translate them into your own union at the boundary.