From claude-initial-setup
Advanced TypeScript type patterns for modeling complex domains safely. Use when the user needs discriminated unions, branded types, template literal types, type guards, exhaustive checking, const assertions, or is designing type-safe APIs and domain models.
npx claudepluginhub versoxbt/claude-initial-setup --plugin claude-initial-setupThis skill uses the workspace's default tool permissions.
Apply advanced type-level patterns to model domains precisely and catch
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Apply advanced type-level patterns to model domains precisely and catch logic errors at compile time instead of runtime.
Use a shared literal property to let TypeScript narrow union members automatically.
interface Loading { status: "loading" }
interface Success<T> { status: "success"; data: T }
interface Failure { status: "error"; error: Error }
type AsyncState<T> = Loading | Success<T> | Failure;
function render(state: AsyncState<string>): string {
switch (state.status) {
case "loading":
return "Loading...";
case "success":
return state.data; // narrowed to Success<string>
case "error":
return state.error.message; // narrowed to Failure
}
}
Guarantee every union variant is handled. If a new variant is added, the compiler flags every switch that misses it.
function assertNever(value: never): never {
throw new Error(`Unhandled value: ${JSON.stringify(value)}`);
}
type Shape =
| { kind: "circle"; radius: number }
| { kind: "rect"; width: number; height: number }
| { kind: "triangle"; base: number; height: number };
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "rect":
return shape.width * shape.height;
case "triangle":
return (shape.base * shape.height) / 2;
default:
return assertNever(shape); // compile error if a case is missing
}
}
Prevent mixing structurally identical types by attaching a phantom brand.
type Brand<T, B extends string> = T & { readonly __brand: B };
type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;
function createUserId(id: string): UserId {
return id as UserId;
}
function createOrderId(id: string): OrderId {
return id as OrderId;
}
function getUser(id: UserId): void { /* ... */ }
const userId = createUserId("u-123");
const orderId = createOrderId("o-456");
getUser(userId); // OK
// getUser(orderId); // Compile error -- OrderId is not UserId
Build type-safe string patterns that the compiler validates.
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type ApiVersion = "v1" | "v2";
type Resource = "users" | "orders" | "products";
type ApiRoute = `/${ApiVersion}/${Resource}`;
// "/v1/users" | "/v1/orders" | "/v1/products" | "/v2/users" | ...
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<"click">; // "onClick"
// Infer parts from template literals
type ExtractResource<T> = T extends `/${string}/${infer R}` ? R : never;
type Route = ExtractResource<"/v1/users">; // "users"
Use as const to preserve literal types and create fully immutable structures.
// Without as const: type is { method: string; url: string }
// With as const: type preserves exact literals
const config = {
method: "GET",
url: "/api/users",
headers: ["Content-Type", "Authorization"],
} as const;
// config.method is "GET", not string
// config.headers is readonly ["Content-Type", "Authorization"]
// Derive union types from const objects
const STATUS_CODES = {
OK: 200,
NOT_FOUND: 404,
SERVER_ERROR: 500,
} as const;
type StatusCode = (typeof STATUS_CODES)[keyof typeof STATUS_CODES];
// 200 | 404 | 500
// Derive from const arrays
const ROLES = ["admin", "editor", "viewer"] as const;
type Role = (typeof ROLES)[number]; // "admin" | "editor" | "viewer"
Create reusable runtime checks that inform the compiler.
interface ApiError {
code: number;
message: string;
}
function isApiError(value: unknown): value is ApiError {
return (
typeof value === "object" &&
value !== null &&
"code" in value &&
"message" in value &&
typeof (value as ApiError).code === "number" &&
typeof (value as ApiError).message === "string"
);
}
async function fetchData(url: string): Promise<string> {
const response = await fetch(url);
const body: unknown = await response.json();
if (isApiError(body)) {
throw new Error(`API error ${body.code}: ${body.message}`);
}
return body as string;
}
String enums without discrimination -- Use discriminated unions instead of plain string enums when variants carry different data. Enums alone cannot narrow.
Overusing as for branded types -- Limit as to brand constructors only. Every other
usage should rely on narrowing.
Forgetting the default: assertNever -- Without the exhaustive check, new union members
silently fall through with undefined behavior.
as const on mutable variables -- as const makes the value deeply readonly.
Do not assign it to a mutable variable and expect mutation to work.
| Pattern | Use Case |
|---|---|
| Discriminated unions | Multi-state data, state machines |
| Exhaustive check (never) | Guarantee all cases handled |
| Branded types | Prevent ID/value mixing |
| Template literal types | Type-safe string patterns |
| const assertions | Immutable configs, derive unions |
| Type guards | Runtime validation with type narrowing |