Get the FREE Ultimate OpenClaw Setup Guide →

typescript-best-practices

Scanned
npx machina-cli add skill Taoidle/plan-cascade/typescript --openclaw
Files (1)
SKILL.md
2.1 KB

TypeScript Best Practices

Code Style

RuleGuideline
FormatterPrettier
LinterESLint + @typescript-eslint
Strict modestrict: true in tsconfig

Type Safety

RuleGuideline
Avoid anyUse unknown + narrowing
Type guardsCustom predicates
Discriminated unionsFor variants
type Result<T> = { success: true; data: T } | { success: false; error: Error };

function isUser(v: unknown): v is User {
  return typeof v === 'object' && v !== null && 'id' in v;
}

Error Handling

class ApiError extends Error {
  constructor(message: string, public status: number) {
    super(message);
    this.name = 'ApiError';
  }
}

async function fetchUser(id: string): Promise<User> {
  const res = await fetch(`/api/users/${id}`);
  if (!res.ok) throw new ApiError('Failed', res.status);
  return res.json();
}

Project Structure

src/{index.ts, types/, services/, utils/}
tests/
package.json, tsconfig.json

Async Patterns

PatternUsage
Promise.allParallel operations
AbortControllerCancellation
const [user, settings] = await Promise.all([fetchUser(id), fetchSettings(id)]);

Anti-Patterns

AvoidUse Instead
as assertionsType guards
! non-null?. and ??
anyunknown + narrowing
// Bad: data as User, user!.name
// Good:
if (isUser(data)) { /* data is User */ }
const name = user?.name ?? 'Unknown';

Testing (Vitest)

describe('Service', () => {
  it('should create', async () => {
    const mock = { save: vi.fn().mockResolvedValue({ id: '1' }) };
    const result = await new Service(mock).create({ name: 'Test' });
    expect(result.id).toBe('1');
  });
});

Source

git clone https://github.com/Taoidle/plan-cascade/blob/master/builtin-skills/typescript/SKILL.mdView on GitHub

Overview

TypeScript/Node.js best practices for writing safe, maintainable code. Covers type safety, async patterns, and error handling to reduce bugs and improve reliability.

How This Skill Works

This guide compiles concrete rules and patterns from the skill content: enforce strict TypeScript usage, apply type guards and discriminated unions, implement a standardized ApiError for HTTP errors, leverage Promise.all for parallel async work and AbortController for cancellation, and avoid common anti-patterns like as assertions and any.

When to Use It

  • When writing TypeScript/Node.js code
  • When reviewing code for type safety and avoiding any
  • When implementing API clients with standardized error handling
  • When building parallel or cancellable async flows
  • When auditing projects for maintainability and anti-patterns

Quick Start

  1. Step 1: Enable strict mode in tsconfig and set up Prettier/ESLint
  2. Step 2: Add type guards, discriminated unions, and avoid any
  3. Step 3: Implement ApiError and use Promise.all with AbortController for async; test with Vitest

Best Practices

  • Enable strict mode (tsconfig strict: true) to catch issues early
  • Use Prettier and ESLint with @typescript-eslint for code quality
  • Prefer type guards and discriminated unions; avoid any
  • Implement ApiError for API call errors with status codes
  • Use Promise.all for parallel async work and AbortController for cancellation; rely on ?. and ?? rather than ! and as

Example Use Cases

  • type Result<T> = { success: true; data: T } | { success: false; error: Error };
  • function isUser(v: unknown): v is User { return typeof v === 'object' && v !== null && 'id' in v; }
  • class ApiError extends Error { constructor(message: string, public status: number) { super(message); this.name = 'ApiError'; } }
  • async function fetchUser(id: string): Promise<User> { const res = await fetch(`/api/users/${id}`); if (!res.ok) throw new ApiError('Failed', res.status); return res.json(); }
  • const [user, settings] = await Promise.all([fetchUser(id), fetchSettings(id)]);

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers