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
View on GitHubed3dai/ed3d-plugins
ed3d-house-style
January 25, 2026
Select agents to install to:
npx add-skill https://github.com/ed3dai/ed3d-plugins/blob/main/plugins/ed3d-house-style/skills/howto-code-in-typescript/SKILL.md -a claude-code --skill howto-code-in-typescriptInstallation paths:
.claude/skills/howto-code-in-typescript/# TypeScript House Style
## Overview
Comprehensive TypeScript coding standards emphasizing type safety, immutability, and integration with Functional Core, Imperative Shell (FCIS) pattern.
**Core principles:**
- Types as documentation and constraints
- Immutability by default prevents bugs
- Explicit over implicit (especially in function signatures)
- Functional Core returns Results, Imperative Shell may throw
- Configuration over decoration/magic
## Quick Self-Check (Use Under Pressure)
When under deadline pressure or focused on other concerns (performance, accuracy, features), STOP and verify:
- [ ] Using `Array<T>` not `T[]`
- [ ] Using `type` not `interface` (unless class contract)
- [ ] Using math.js for money/currencies/complex math
- [ ] Parameters are `readonly` or `Readonly<T>`
- [ ] Using `unknown` not `any`
- [ ] Using `null` for absent values (not `undefined`)
- [ ] Using function declarations (not const arrow) for top-level functions
- [ ] Using named exports (not default exports)
- [ ] Using `===` not `==`
- [ ] Using `.sort((a, b) => a - b)` for numeric arrays
- [ ] Using `parseInt(x, 10)` with explicit radix
**Why this matters:** Under pressure, you'll default to muscle memory. These checks catch the most common violations.
## Type Declarations
### Type vs Interface
**Always use `type` except for class contracts.**
```typescript
// 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