Skip to content
Development
Skill

/typescript-standards

Shared TypeScript coding standards for strict, immutable, type-safe code.

From plugin
sdd
4359 skills7 agents3 commands

Claude Code

$ npx -y skills add LiorCohen/sdd --skill typescript-standards --agent claude-code

SKILL.md

typescript-standards.SKILL.md
name: typescript-standards
description: Shared TypeScript coding standards for strict, immutable, type-safe code.

TypeScript Standards Skill

Shared standards for all TypeScript code in this methodology (backend and frontend).

---

Strict TypeScript Configuration

All projects must use these TypeScript compiler options:

// tsconfig.json requirements
{
  "strict": true,
  "noImplicitAny": true,
  "strictNullChecks": true,
  "strictFunctionTypes": true,
  "strictPropertyInitialization": true,
  "noImplicitThis": true,
  "alwaysStrict": true
}

**Rules:**

  • All types explicitly declared
  • No `any` unless absolutely unavoidable (must be justified)
  • Prefer `unknown` over `any`

---

Immutability (Non-Negotiable)

Use `readonly` on all properties, `ReadonlyArray<T>` for arrays, `Readonly<T>` / `ReadonlyMap` / `ReadonlySet` for generic types. Use `const` exclusively (never `let` or `var`). Use spread operators for updates — never mutate.

See [immutability.md](resources/immutability.md) for full examples and functional alternatives to `let`.

---

Banned Mutable Operations

**CRITICAL:** `.push()`, `.pop()`, `.shift()`, `.unshift()`, `.splice()`, `.sort()`, `.reverse()`, `.fill()` on arrays; `obj.prop = x`, `delete obj.prop`, `Object.assign(target, ...)` on objects; `.set()`, `.delete()`, `.add()`, `.clear()` on Maps/Sets — all strictly forbidden. Use spread operators and immutable patterns instead.

See [banned-operations.md](resources/banned-operations.md) for the complete reference tables with alternatives.

---

Arrow Functions Only

// GOOD: Arrow functions
const createUser = async (deps: Dependencies, args: CreateUserArgs): Promise<CreateUserResult> => {
  // ...
};

const handleClick = () => {
  // ...
};

// BAD: function keyword
async function createUser(deps: Dependencies, args: CreateUserArgs): Promise<CreateUserResult> {
  // ...
}

function handleClick() {
  // ...
}

**Rule:** Use arrow functions exclusively. Never use the `function` keyword.

---

No Classes or Inheritance

**CRITICAL:** Never use classes or inheritance unless creating a subclass of Error.

// GOOD: Types and functions
type User = {
  readonly id: string;
  readonly email: string;
  readonly createdAt: Date;
};

const createUser = (args: CreateUserArgs): User => ({
  id: generateId(),
  email: args.email,
  createdAt: new Date(),
});

// GOOD: Error subclass (only valid use of class)
class ValidationError extends Error {
  constructor(
    message: string,
    readonly field: string,
    readonly code: string
  ) {
    super(message);
    this.name = 'ValidationError';
  }
}

class NotFoundError extends Error {
  constructor(resource: string, id: string) {
    super(`${resource} with id ${id} not found`);
    this.name = 'NotFoundError';
  }
}

// BAD: Classes for domain objects
class User {
  constructor(
    public id: string,
    public email: string
  ) {}

  updateEmail(email: string) {
    this.email = email;  // Mutation!
  }
}

// BAD: Inheritance hierarchies
class Animal { /* ... */ }
class Dog extends Animal { /* ... */ }

// BAD: Service classes
class UserService {
  constructor(private db: Database) {}

  async createUser(args: CreateUserArgs) { /* ... */ }
}

**Why:**

  • Classes encourage mutation (methods that modify `this`)
  • Inheritance creates tight coupling and fragile hierarchies
  • Functions with explicit dependencies are easier to test and reason about
  • Error subclasses are the exception because they integrate with JavaScript's error handling (`instanceof`, stack traces)

---

Native JavaScript Only

// GOOD: Native methods
const filtered = users.filter(u => u.active);
const updated = { ...user, email: newEmail };
const mapped = Object.fromEntries(
  Object.entries(obj).map(([k, v]) => [k, v * 2])
);

// BAD: External utility libraries
import { map } from 'lodash';      // Never
import { produce } from 'immer';   // Never
import * as R from 'ramda';        // Never

**Rule:** Use only native JavaScript/TypeScript features. No utility libraries like lodash, ramda, or immer.

**Why:** Reduces bundle size, eliminates dependencies, forces understanding of native methods, ensures code remains maintainable without external library knowledge.

---

Module System Rules

Named exports only (never default exports). ES modules only (never CommonJS). `index.ts` files contain only imports/exports (no logic). Always import through `index.ts` (never bypass to implementation files). Inside a module, never import from its own `index.ts` — use relative paths to siblings. No file extensions in imports. Use `@/` path alias for deep imports (2+ directory levels). Use `import type` for type-only imports.

See [module-system.md](resources/module-system.md) for full rules with examples.

---

Interface vs Type

**Rule:** `interface` for function-only contracts (callbacks, loggers, handlers). `type` for everything else. Data types should not contain functions.

// GOOD: interface for function-only contracts
interface Logger {
  readonly info: (message: string, data?: unknown) => void;
  readonly warn: (message: string, data?: unknown) => void;
  readonly error: (message: string, data?: unknown) => void;
}

// GOOD: type for data shapes
type User = {
  readonly id: string;
  readonly email: string;
  readonly createdAt: Date;
};

type ServerMode = 'api' | 'worker' | 'cron';

type HelmSettings = HelmServerSettings | HelmWebappSettings;

// BAD: interface for data
interface User {
  readonly id: string;
  readonly email: string;
}

// BAD: type for function contracts
type Logger = {
  readonly info: (message: string) => void;
};

// BAD: functions inside data types
type User = {
  readonly id: string;
  readonly getDisplayName: () => string;  // Data types should not have methods
};

---

Semantic Type Aliases

Use type aliases to give meaning to primitives. A function accepting `Milliseconds` is

Read more
@liorcohen
Ships withsdd

Structure for AI-assisted development AI coding assistants are powerful but chaotic. You prompt, you get code, but then what?

4359 skills7 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
43
Star history of LiorCohen/sdd on GitHub, a chart by star-history.com

Other skills on sdd.

agents-standards

agents-standards

Standards for authoring SDD plugin agents — frontmatter, self-containment, skill references, and no-user-interaction rules.

@liorcohen@liorcohenInstall Skill
commands-standards

commands-standards

Standards for authoring SDD plugin commands — frontmatter, user interaction, skill/agent invocation, CLI integration, and output…

@liorcohen@liorcohenInstall Skill
commit

commit

Create a commit following repository guidelines with proper versioning and changelog updates.

@liorcohen@liorcohenInstall Skill
critic

critic

Two-step self-review at every task lifecycle phase. Step 1 (this skill) runs in-context to gather session signals — files read vs…

@liorcohen@liorcohenInstall Skill
d2

d2

D2 diagramming language reference for architecture diagrams, sequence diagrams, grid layouts, SQL tables, and class diagrams.…

@liorcohen@liorcohenInstall Skill
docs-standards

docs-standards

Writes and maintains user-facing documentation for the SDD plugin. Proactively detects when docs are out of sync with plugin…

@liorcohen@liorcohenInstall Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about typescript-standards.

Which coding agents can use typescript-standards?
typescript-standards installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.