From typescript-standards
Enforce type-safe TypeScript patterns with Zod validation, pattern matching, and discriminated unions to prevent runtime errors. Use when writing TypeScript code, reviewing for type safety, designing data validation flows, or refactoring to eliminate impossible states.
How this skill is triggered — by the user, by Claude, or both
Slash command
/typescript-standards:enforce-ts-standardsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Project-specific TypeScript rules and guidelines enforcing type safety at system boundaries and preventing impossible application states.
Project-specific TypeScript rules and guidelines enforcing type safety at system boundaries and preventing impossible application states.
Use this skill when:
This skill applies to production code, shared utilities, and core business logic.
Apply pragmatism in these specific cases:
Code actively being migrated to type safety requires strategic pragmatism. Document escape hatches with // TODO: improve type safety comments. Converting a legacy codebase is a multi-step project, not a single skill application. Focus on new code and critical paths first.
External libraries that don't follow these standards are unavoidable. Solution: Create adapter/bridge modules that:
Example:
// old-lib-adapter.ts - bridge the gap
import someLib from 'old-lib';
export function adaptLibFunction(input: unknown) {
// Accept old lib's loose types here
const result = someLib.process(input as any);
// Validate and parse at our boundary
return resultSchema.parse(result);
}
These rules assume your project uses Zod for validation and ts-pattern for matching. If your project chooses different tools:
Example: If using io-ts instead of Zod, follow the same boundary validation pattern with io-ts.decode().
any, as, !. Use unknown + narrowing..exhaustive().// ❌ BAD
function process(data: any) { return data.value; }
const user = response as User;
const name = user!.name;
// ✅ GOOD
function process(data: unknown) {
if (isUser(data)) return data.value;
}
const user = UserSchema.parse(response);
const name = user?.name ?? 'default';
// Schema is source of truth
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
role: z.enum(['admin', 'user', 'guest'])
});
type User = z.infer<typeof UserSchema>;
// Parse at boundary, trust internally
async function fetchUser(id: string): Promise<User> {
const json = await fetch(`/api/users/${id}`).then(r => r.json());
return UserSchema.parse(json);
}
import { match, P } from 'ts-pattern';
const result = match(state)
.with({ status: 'loading' }, () => <Spinner />)
.with({ status: 'success', data: P.select() }, (data) => <Data data={data} />)
.with({ status: 'error' }, ({ error }) => <Error error={error} />)
.exhaustive();
// ❌ Allows impossible states
type State = { status: string; data?: T; error?: Error };
// ✅ Prevents impossible states
type State<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; error: Error };
| Category | Rule |
|---|---|
| Files | kebab-case.ts |
| Variables/Functions | camelCase |
| Types/Interfaces | PascalCase |
| Constants | UPPER_SNAKE_CASE |
| Generics | TData, TKey |
| Exports | Named only (no default) |
| Imports | import type for types |
| Enums | Never (use unions + as const) |
For comprehensive rules, advanced patterns, and edge cases, consult ./reference/typescript-rules.md:
| Topic | Why Check | When |
|---|---|---|
| TIER 1 - Critical | Foundation rules on type safety | Always - understand before coding |
| TIER 2 - Very Important | Return types, brand types, readonly | When building boundaries |
| TIER 3 - Important | Naming conventions, exports, enums | During code review |
| TIER 4 - Advanced | Zod deep dives, ts-pattern guards, recursion | When solving complex problems |
| Pragmatism Section | Legacy code strategies | When modernizing existing code |
Key Topics in Reference:
any types (adapter pattern)Q: When do I need Zod vs type guards? Zod for untrusted boundaries (APIs, user input, env). Type guards for trusted internal data.
Q: Should I use brand types? When you have similar primitives (UserId, ProductId, OrderId). See TIER 2 in reference.
Q: Can I use as type assertions?
Only as last resort. Try: validation → satisfies → type narrowing → guards → assertions.
Q: When should I relax these standards?
See "When NOT to Use This Skill" section above. Document escapes with // TODO: improve type safety.
npx claudepluginhub fcamblor/cc-plugins --plugin typescript-standardsGuides TypeScript code with pedantic best practices: strict tsconfig flags like noUncheckedIndexedAccess, discriminated unions over assertions, Zod runtime validation, barrel exports, as const, ESLint rules.
Provides advanced TypeScript patterns for type design with discriminated unions and branded types, Zod runtime validation, Result-based error handling, and monorepo configuration with Turborepo/Nx/pnpm.
Enforces TypeScript conventions for strict, type-safe code: no `any` use unknown, interfaces vs types, literal unions over enums, discriminated unions, type narrowing with guards, branded types, and anti-pattern avoidance.