| name | code:typescript |
| description | TypeScript coding practices and idioms. Strict mode, discriminated unions, Zod validation, type guards, utility types.
<example>
Context: User is writing TypeScript code
user: "implement a type-safe API client"
</example>
<example>
Context: User needs TypeScript patterns
user: "how should I model this state with unions"
</example>
|
Tools Reference
Built-in Tools
| Tool | Purpose |
|---|
Read | Read .ts files |
Write | Create new TypeScript files |
Edit | Modify TypeScript code |
Bash | Run tsc, npm, npx, vitest, eslint, prettier |
Glob | Find TypeScript files (*.ts) |
Grep | Search TypeScript code |
Related Skills
marauder:code:typescript-cli - Commander.js CLI development
marauder:code:typescript-test - Vitest testing
marauder:code:typescript-tooling - Lint/format/typecheck/validate
TypeScript Coding Practices
Modern TypeScript idioms focused on type safety and readability.
Strict Mode (Non-Negotiable)
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"exactOptionalPropertyTypes": true,
"noPropertyAccessFromIndexSignature": true
}
}
Discriminated Unions
State Modeling
type RequestState<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; error: Error };
function render(state: RequestState<User>) {
switch (state.status) {
case 'idle': return <Placeholder />;
case 'loading': return <Spinner />;
case 'success': return <UserCard user={state.data} />;
case 'error': return <ErrorMessage error={state.error} />;
}
}
Const Assertions
const roles = ['admin', 'user', 'guest'] as const;
type Role = (typeof roles)[number];
Type Guards
function isAdmin(person: User | Admin): person is Admin {
return person.type === 'admin';
}
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== 'string') {
throw new Error(`Expected string, got ${typeof value}`);
}
}
Zod for Runtime Validation
import { z } from 'zod';
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
name: z.string().min(1).max(100),
role: z.enum(['admin', 'user', 'guest']),
});
type User = z.infer<typeof UserSchema>;
function parseUser(data: unknown): User {
return UserSchema.parse(data);
}
Utility Types
type UserUpdate = Partial<User>;
type UserPreview = Pick<User, 'id' | 'name'>;
type PublicUser = Omit<User, 'password'>;
type ImmutableUser = Readonly<User>;
type UserById = Record<string, User>;
Avoid any
function parse(json: string): any { ... }
function parse(json: string): unknown { ... }
function parseUser(json: string): User {
const data = JSON.parse(json);
return UserSchema.parse(data);
}
Result Type Pattern
type Result<T, E = Error> =
| { ok: true; value: T }
| { ok: false; error: E };
function divide(a: number, b: number): Result<number, string> {
if (b === 0) {
return { ok: false, error: 'Division by zero' };
}
return { ok: true, value: a / b };
}
Type-Only Imports
import type { User, Order } from './models';
import { createUser } from './services';
Barrel Exports
export { User, type UserCreate } from './user';
export { Order, type OrderItem } from './order';
Class Patterns
class Order {
private constructor(
public readonly id: string,
public readonly items: OrderItem[],
) {}
static create(items: OrderItem[]): Order {
return new Order(crypto.randomUUID(), items);
}
static fromJson(data: unknown): Order {
const parsed = OrderSchema.parse(data);
return new Order(parsed.id, parsed.items);
}
}