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…
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
Claude Code
$ npx -y skills add ed3dai/ed3d-plugins --skill howto-code-in-typescript --agent claude-code
Codex
$ npx skills add ed3dai/ed3d-plugins --skill howto-code-in-typescript -a codex -y
Cursor
$ npx skills add ed3dai/ed3d-plugins --skill howto-code-in-typescript -a cursor -y
Gemini CLI
$ npx skills add ed3dai/ed3d-plugins --skill howto-code-in-typescript -a gemini-cli -y
GitHub Copilot
$ npx skills add ed3dai/ed3d-plugins --skill howto-code-in-typescript -a github-copilot -y
OpenCode
$ npx skills add ed3dai/ed3d-plugins --skill howto-code-in-typescript -a opencode -y
Windsurf
$ npx skills add ed3dai/ed3d-plugins --skill howto-code-in-typescript -a windsurf -y
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.
Use when analyzing a large corpus of text, code, or data that exceeds a single agent's effective context - orchestrates parallel…
Use when creating a new Claude Code plugin or setting up plugin structure - provides complete file organization, manifest format,…
Use when creating specialized subagents for Claude Code plugins or the Task tool - covers description writing for…
Use when creating, releasing, or maintaining a Claude Code Plugin Marketplace - covers marketplace.json schema, version…
Use when completing development phases or branches to identify and update CLAUDE.md or AGENTS.md files that may have become stale…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.