Write clean, type-safe TypeScript code using modern patterns, strict configuration, and best practices. Use when writing TypeScript code, configuring projects, or solving type-related challenges.
Writes clean, type-safe TypeScript using modern patterns and strict configuration. Triggers when writing TypeScript code, configuring tsconfig.json, or solving type-related challenges.
/plugin marketplace add codethread/claude-code-plugins/plugin install langs@codethread-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/best-practices-2025.mdWrite clean, type-safe TypeScript code that leverages the full power of the type system to catch bugs at compile time.
Use this skill when:
Choose the right construct:
| Use Case | Use | Not |
|---|---|---|
| Object shapes | interface | type |
| Unions/primitives | type | interface |
| Dynamic data | unknown | any |
| State machines | Discriminated unions | Complex conditionals |
| Domain types | Branded types | Plain primitives |
Example:
// ✅ Correct choices
interface User {
id: number;
name: string;
} // Object shape
type Status = "idle" | "loading" | "success"; // Union
type USD = number & { readonly __brand: "USD" }; // Branded type
// ❌ Wrong choices
type User = { id: number }; // Use interface
interface Status {
/* ... */
} // Can't do unions
For finite states, always use discriminated unions to eliminate impossible states:
type ApiState =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: string }
| { status: "error"; message: string };
// Exhaustiveness checking
function handle(state: ApiState) {
switch (state.status) {
case "success":
return state.data;
case "error":
return state.message;
case "idle":
return "Not started";
case "loading":
return "Loading...";
default:
const _exhaustive: never = state; // Compiler error if cases missing
throw new Error("Unhandled state");
}
}
Always validate external data with runtime checks:
// Type guard pattern
function isUser(data: unknown): data is User {
return (
typeof data === "object" &&
data !== null &&
"id" in data &&
typeof (data as any).id === "number"
);
}
// Schema validation (preferred for APIs)
import { z } from "zod";
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
});
type User = z.infer<typeof UserSchema>;
const user = UserSchema.parse(apiData); // Runtime validation + types
Never use type assertions without validation:
// ❌ BAD: No runtime check
const user = data as User;
// ✅ GOOD: Validated first
if (isUser(data)) {
// data is User here
}
For new projects, enable strict mode plus:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"noPropertyAccessFromIndexSignature": true,
"moduleResolution": "bundler"
}
}
Why these matter:
noUncheckedIndexedAccess - Prevents undefined access bugsexactOptionalPropertyTypes - Distinguishes missing from undefinedmoduleResolution: "bundler" - Optimized for Vite/esbuildBarrel files: Avoid for internal code (75% faster builds)
// ❌ BAD: Internal barrel
// src/components/index.ts
export * from "./Button";
// ✅ GOOD: Direct imports + path aliases
// tsconfig.json: "paths": { "@/components/*": ["src/components/*"] }
import { Button } from "@/components/Button";
Only use barrel files for:
type UserPreview = Pick<User, "id" | "name">; // Extract subset
type PublicUser = Omit<User, "email">; // Remove fields
type UpdateDto = Partial<User>; // Make optional
type CompleteUser = Required<User>; // Make required
type ImmutableUser = Readonly<User>; // Make readonly
type UserType = ReturnType<typeof getUser>; // Extract return type
// Catch with unknown
try {
} catch (err: unknown) {
if (err instanceof Error) {
/* ... */
}
}
// Result types for expected failures
type Result<T, E = Error> =
| { success: true; value: T }
| { success: false; error: E };
const config: Readonly<Config> = {
/* ... */
};
const numbers: readonly number[] = [1, 2, 3];
const ROUTES = { home: "/" } as const; // Deep readonly + literal types
For comprehensive information on advanced patterns, configuration options, or specific features, read:
references/best-practices-2025.md - Full TypeScript best practices guideThe reference includes:
Before completing TypeScript code:
any types (or explicitly justified)neverThis skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.