Typescript
Skill nimadorostkar/Claude-Skills-collection/skills/languages/typescript
Use when writing or hardening TypeScript in strict mode. Covers advanced types, discriminated unions, runtime validation at trust boundaries, generics, and removing `any` from an existing codebase.From its SKILL.md
npx -y skills add nimadorostkar/Claude-Skills-collection --skill typescriptAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
4.4 KB, 956 tokens by cl100k_base, as published. Nobody here has run it
TypeScript
Purpose
Use the type system to make invalid states unrepresentable. This skill covers strict-mode TypeScript, the advanced type features worth reaching for, and the discipline of validating untrusted data exactly once — at the boundary.
When to Use
- Starting a TypeScript project or tightening
tsconfig.json. - Removing
anyand unchecked casts from an existing codebase. - Modeling a domain with discriminated unions and exhaustive matching.
- Writing a typed API client or SDK.
- Debugging inference failures in generic code.
Capabilities
- Strict compiler configuration and incremental adoption paths.
- Discriminated unions, template literal types, conditional and mapped types.
- Generic constraints, inference control, and
satisfies. - Runtime schema validation with Zod, wired to inferred static types.
- Type-safe error handling with
Result-style unions.
Inputs
- Source files and the current
tsconfig.json. - Runtime target (Node, browser, edge, Deno, Bun).
- External data shapes: API responses, environment variables, user input.
Outputs
- Source that compiles under
strict: truewith zeroany. - Schemas for every trust boundary, with static types derived from them.
- A
tsconfig.jsonreflecting the target runtime.
Workflow
- Set the gate — Enable
strict,noUncheckedIndexedAccess, andexactOptionalPropertyTypes. Everything else follows from the compiler's complaints. - Type the boundaries — Define schemas for every input that crosses into your program: HTTP payloads, env vars, config files, message queues.
- Model the domain — Replace boolean flags and optional grab-bags with discriminated unions.
- Implement inward — Internal code trusts its types because the boundary already validated them.
- Verify —
tsc --noEmitand lint with@typescript-eslint,no-explicit-anyset to error.
Best Practices
- Never use
asto silence the compiler. It is an assertion, not a check; it lies at runtime. - Prefer
unknownoveranyat every boundary, then narrow. - Derive types from schemas (
z.infer), never maintain both by hand. - Use
satisfiesto validate an object literal against a type while preserving its narrow inferred type. - Add an exhaustiveness check (
never) to every union switch — it turns a future missing case into a compile error. - Do not export types you do not intend to support. A public type is an API contract.
Examples
Boundary validation with derived types:
import { z } from "zod";
const Config = z.object({
port: z.coerce.number().int().positive(),
databaseUrl: z.string().url(),
logLevel: z.enum(["debug", "info", "warn", "error"]).default("info"),
});
export type Config = z.infer<typeof Config>;
export function loadConfig(env: NodeJS.ProcessEnv): Config {
const parsed = Config.safeParse({
port: env.PORT,
databaseUrl: env.DATABASE_URL,
logLevel: env.LOG_LEVEL,
});
if (!parsed.success) {
throw new Error(`Invalid configuration:\n${parsed.error.message}`);
}
return parsed.data;
}
Exhaustive discriminated union:
type Job =
| { status: "queued"; queuedAt: Date }
| { status: "running"; startedAt: Date; workerId: string }
| { status: "failed"; error: string; attempts: number };
function describe(job: Job): string {
switch (job.status) {
case "queued":
return `Queued at ${job.queuedAt.toISOString()}`;
case "running":
return `Running on ${job.workerId}`;
case "failed":
return `Failed after ${job.attempts} attempts: ${job.error}`;
default: {
const unreachable: never = job;
throw new Error(`Unhandled job status: ${JSON.stringify(unreachable)}`);
}
}
}
Notes
noUncheckedIndexedAccessis the single highest-value flag most codebases are missing: it makesarr[i]returnT | undefined, which is the truth.- Declaration files (
.d.ts) fromDefinitelyTypedare frequently wrong. Verify against runtime behavior before trusting them. - Type-level programming is a cost. If a conditional type takes more than a minute to read, prefer a simpler runtime check.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.