doing-a-simple-two-sta…
Use when analyzing a large corpus of text, code, or data that exceeds a single agent's effective context - orchestrates parallel Worker subagents, Critic…
Use when writing TypeScript code, reviewing TS implementations, or making decisions about type declarations, function styles, or naming conventions - comprehensive house style covering type vs interface rules, function declarations, FCIS integration, immutability patterns, and
$ npx -y skills add ed3dai/ed3d-plugins --skill howto-code-in-typescript --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/howto-code-in-typescriptContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when writing TypeScript code, reviewing TS implementations, or making decisions about type declarations, function styles, or naming conventions - comprehensive house style covering type vs interface rules, function declarations, FCIS integration, immutability patterns, and
name: howto-code-in-typescript description: Use when writing TypeScript code, reviewing TS implementations, or making decisions about type declarations, function styles, or naming conventions - comprehensive house style covering type vs interface rules, function declarations, FCIS integration, immutability patterns, and type safety enforcement user-invocable: false
Comprehensive TypeScript coding standards emphasizing type safety, immutability, and integration with Functional Core, Imperative Shell (FCIS) pattern.
**Core principles:**
When under deadline pressure or focused on other concerns (performance, accuracy, features), STOP and verify:
**Why this matters:** Under pressure, you'll default to muscle memory. These checks catch the most common violations.
**Always use `type` except for class contracts.**
// GOOD: type for object shapes
type UserData = {
readonly id: string;
name: string;
email: string | null;
};
// GOOD: interface for class contract
interface IUserRepository {
findById(id: string): Promise<User | null>;
}
class UserRepository implements IUserRepository {
// implementation
}
// BAD: interface for object shape
interface UserData {
id: string;
name: string;
}**Rationale:** Types compose better with unions and intersections, support mapped types, and avoid declaration merging surprises. Interfaces are only for defining what a class must implement.
**IMPORTANT:** Even when under deadline pressure, even when focused on other concerns (financial accuracy, performance optimization, bug fixes), take 2 seconds to ask: "Is this a class contract?" If no, use `type`. Don't default to `interface` out of habit.
| Suffix | Usage | Example | |--------|-------|---------| | `FooOptions` | Function parameter objects (3+ args or any optional) | `ProcessUserOptions` | | `FooConfig` | Persistent configuration from storage | `DatabaseConfig` | | `FooResult` | Discriminated union return types | `ValidationResult` | | `FooFn` | Function/callback types | `TransformFn<T>` | | `FooProps` | React component props | `ButtonProps` | | `FooState` | State objects (component/application) | `AppState` |
| Element | Convention | Example | |---------|-----------|---------| | Variables & functions | camelCase | `userName`, `getUser()` | | Types & classes | PascalCase | `UserData`, `UserService` | | Constants | UPPER_CASE | `MAX_RETRY_COUNT`, `API_ENDPOINT` | | Files | kebab-case | `user-service.ts`, `process-order.ts` |
**Use is/has/can/should/will prefixes. Avoid negative names.**
// GOOD
const isActive = true;
const hasPermission = checkPermission();
const canEdit = user.role === 'admin';
const shouldRetry = attempts < MAX_RETRIES;
const willTimeout = elapsed > threshold;
// Also acceptable: adjectives for state
type User = {
active: boolean;
visible: boolean;
disabled: boolean;
};
// BAD: negative names
const isDisabled = false; // prefer isEnabled
const notReady = true; // prefer isReady**Use for functions with 3+ arguments OR any optional arguments.**
type ProcessUserOptions = {
readonly name: string;
readonly email: string;
readonly age: number;
readonly sendWelcome?: boolean;
};
// GOOD: destructure in body, not in parameters
function processUser(options: ProcessUserOptions): void {
const {name, email, age, sendWelcome = true} = options;
// implementation
}
// BAD: inline destructuring in parameters
function processUser({name, email, age}: {name: string, email: string, age: number}) {
// causes duplication when destructuring
}
// BAD: not using options pattern for 3+ args
function processUser(name: string, email: string, age: number, sendWelcome?: boolean) {
// hard to call, positional arguments
}**Always use discriminated unions for Result types. Integrate with neverthrow.**
// GOOD: discriminated union with success/error
type ValidationResult =
| { success: true; data: ValidUser }
| { success: false; error: ValidationError };
// GOOD: use neverthrow for Result types
import {Result, ok, err} from 'neverthrow';
type ValidationError = {
field: string;
message: string;
};
function validateUser(data: Readonly<UserData>): Result<ValidUser, ValidationError> {
if (!data.email) {
return err({field: 'email', message: 'Email is required'});
}
return ok({...data, validated: true});
}
// Usage
const result = validateUser(userData);
if (result.isOk()) {
console.log(result.value); // ValidUser
} else {
console.error(result.error); // ValidationError
}**Rule:** Functional Core functions should return `Result<T, E>` types. Imperative Shell functions may throw exceptions for HTTP errors and similar.
**Use `function` declarations for top-level functions. Use arrow functions for inline callbacks.**
// GOOD: function decla
Ed's repo of Claude Code plugins, centered around a research-plan-implement workflow. Only a tiny bit cursed. If you're lucky.
Repo: ed3dai/ed3d-plugins
Use when analyzing a large corpus of text, code, or data that exceeds a single agent's effective context - orchestrates parallel Worker subagents, Critic…
Use when creating a new Claude Code plugin or setting up plugin structure - provides complete file organization, manifest format, and component definitions for…
Use when creating specialized subagents for Claude Code plugins or the Task tool - covers description writing for auto-delegation, tool selection, prompt…
Use when creating, releasing, or maintaining a Claude Code Plugin Marketplace - covers marketplace.json schema, version management, release checklists,…
Use when completing development phases or branches to identify and update CLAUDE.md or AGENTS.md files that may have become stale - analyzes what changed,…