typescript-write

TypeScript/JavaScript Development Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "typescript-write" with this command: npx skills add acaprino/alfio-claude-plugins/acaprino-alfio-claude-plugins-typescript-write

TypeScript/JavaScript Development Skill

When to Invoke

  • Writing new TypeScript or JavaScript files

  • Refactoring existing TS/JS code

  • Reviewing code for type safety and best practices

  • Converting JavaScript to TypeScript

  • Designing module APIs and type interfaces

  • Fixing type errors or improving type coverage

Code Style

Naming Conventions

  • camelCase for variables, functions, parameters

  • PascalCase for types, interfaces, classes, enums, React components

  • UPPER_SNAKE_CASE for constants and enum members

  • Prefix interfaces with I only if project convention requires it - otherwise plain PascalCase

  • Boolean variables: use is , has , should , can prefixes (isLoading , hasPermission )

  • Event handlers: handleClick , onSubmit pattern

File Organization

  • One primary export per file when possible

  • Group related types with their implementation

  • Barrel exports (index.ts ) for public module APIs only - avoid deep barrel re-exports

  • File naming: kebab-case.ts for utilities, PascalCase.tsx for React components

Import Ordering

  • Node built-in modules (node:fs , node:path )

  • External packages (react , lodash )

  • Internal aliases (@/utils , @/components )

  • Relative imports (./helpers , ../types )

  • Type-only imports (import type { Foo } )

  • Blank line between each group

TypeScript Patterns

Strict Mode

  • Enable strict: true in tsconfig.json

  • never disable individual strict checks

  • No // @ts-ignore or // @ts-expect-error without an explanatory comment

  • Prefer unknown over any

  • narrow with type guards

Proper Typing

  • Avoid any

  • use unknown and narrow, or define a proper type

  • Prefer interface for object shapes that may be extended

  • Prefer type for unions, intersections, mapped types, and utility types

  • Use readonly for properties that should not be mutated

  • Use as const for literal type inference on objects and arrays

Discriminated Unions

type Result<T> = | { success: true; data: T } | { success: false; error: Error };

function handle<T>(result: Result<T>) { if (result.success) { // result.data is T here return result.data; } // result.error is Error here throw result.error; }

Type Guards

// User-defined type guard function isString(value: unknown): value is string { return typeof value === "string"; }

// Assertion function function assertDefined<T>(value: T | undefined, name: string): asserts value is T { if (value === undefined) { throw new Error(Expected ${name} to be defined); } }

Generic Constraints

// Constrain generics to what you actually need function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }

// Use defaults for common cases type ApiResponse<T = unknown> = { data: T; status: number; timestamp: string; };

Utility Types

  • Partial<T>

  • all properties optional (use for update/patch operations)

  • Required<T>

  • all properties required

  • Pick<T, K>

  • select subset of properties

  • Omit<T, K>

  • exclude properties

  • Record<K, V>

  • typed key-value map

  • Extract<T, U> / Exclude<T, U>

  • filter union members

  • Prefer built-in utility types over manual type manipulation

Enums vs Union Types

  • Prefer string union types for simple sets: type Status = "active" | "inactive"

  • Use const enum only if you need numeric values and tree-shaking

  • Use regular enum when you need runtime reverse mapping or iteration

React Patterns

Component Typing

// Function components - type props inline or with interface interface ButtonProps { label: string; variant?: "primary" | "secondary"; onClick: () => void; children?: React.ReactNode; }

function Button({ label, variant = "primary", onClick, children }: ButtonProps) { return <button className={variant} onClick={onClick}>{children ?? label}</button>; }

Hooks Rules

  • Call hooks at the top level only - never inside conditions, loops, or nested functions

  • Custom hooks must start with use prefix

  • Specify dependency arrays accurately - never suppress exhaustive-deps lint

  • Use useCallback for functions passed as props to memoized children

  • Use useMemo for expensive computations - not for every variable

State Management

  • Colocate state as close to where it is used as possible

  • Lift state up only when siblings need to share it

  • Use useReducer for complex state with multiple sub-values or transitions

  • Context for truly global state (theme, auth, locale) - not for frequently changing data

Event Handling

// Type event handlers properly function handleChange(e: React.ChangeEvent<HTMLInputElement>) { setValue(e.target.value); }

function handleSubmit(e: React.FormEvent<HTMLFormElement>) { e.preventDefault(); // ... }

Testing

File Naming

  • Test files: *.test.ts or *.spec.ts alongside the source file

  • Or in tests/ directory mirroring the source structure

  • Test utilities: test-utils.ts or testing/ directory

Test Structure

describe("calculateTotal", () => { it("returns 0 for empty cart", () => { expect(calculateTotal([])).toBe(0); });

it("sums item prices with quantities", () => { const items = [ { price: 10, quantity: 2 }, { price: 5, quantity: 1 }, ]; expect(calculateTotal(items)).toBe(25); });

it("throws for negative quantities", () => { expect(() => calculateTotal([{ price: 10, quantity: -1 }])).toThrow(); }); });

Assertion Patterns

  • Use toBe for primitives, toEqual for objects/arrays

  • Use toThrow for error cases - wrap in arrow function

  • Use toHaveBeenCalledWith for spy/mock assertions

  • Prefer specific matchers over generic toBeTruthy /toBeFalsy

  • Type test fixtures and mocks - avoid as any in tests

Mocking

  • Mock external dependencies, not internal implementation

  • Use vi.fn() (Vitest) or jest.fn() for function mocks

  • Use vi.spyOn / jest.spyOn to mock methods while preserving type safety

  • Reset mocks in beforeEach or use afterEach(() => vi.restoreAllMocks())

Common Anti-Patterns

Using any Instead of Proper Types

// BAD function parse(data: any) { return data.name; }

// GOOD function parse(data: unknown): string { if (typeof data === "object" && data !== null && "name" in data) { return String((data as { name: unknown }).name); } throw new Error("Invalid data"); }

Non-Null Assertion Overuse

// BAD const name = user!.name!;

// GOOD if (!user?.name) throw new Error("User name required"); const name = user.name;

Barrel File Performance Issues

// BAD - importing everything through deep barrel import { Button } from "@/components"; // pulls entire component tree

// GOOD - direct import import { Button } from "@/components/Button";

Ignoring Return Types

// BAD - return type inferred as complex union function getData(id: string) { if (!id) return null; return fetch(/api/${id}).then(r => r.json()); }

// GOOD - explicit return type async function getData(id: string): Promise<ApiResponse | null> { if (!id) return null; const r = await fetch(/api/${id}); return r.json() as Promise<ApiResponse>; }

Mutating Function Parameters

// BAD function addItem(items: Item[], item: Item) { items.push(item); // mutates input return items; }

// GOOD function addItem(items: readonly Item[], item: Item): Item[] { return [...items, item]; }

Error Handling

Result Pattern

type Result<T, E = Error> = | { ok: true; value: T } | { ok: false; error: E };

async function fetchUser(id: string): Promise<Result<User>> { try { const res = await fetch(/api/users/${id}); if (!res.ok) return { ok: false, error: new Error(HTTP ${res.status}) }; const user = await res.json(); return { ok: true, value: user }; } catch (e) { return { ok: false, error: e instanceof Error ? e : new Error(String(e)) }; } }

Async Error Handling

  • Always try/catch around await calls that can fail

  • Never use .catch() and await on the same promise chain

  • Prefer returning error results over throwing in library code

  • Throw only for programmer errors (assertion failures, invariant violations)

  • Log errors at the boundary, not at every level

Error Boundaries (React)

  • Wrap major UI sections in error boundaries

  • Provide meaningful fallback UI - not blank screens

  • Log errors to monitoring service in componentDidCatch

  • Reset error boundary state on navigation changes

Typed Errors

class NotFoundError extends Error { readonly code = "NOT_FOUND" as const; constructor(resource: string, id: string) { super(${resource} ${id} not found); this.name = "NotFoundError"; } }

class ValidationError extends Error { readonly code = "VALIDATION" as const; constructor(public readonly fields: Record<string, string>) { super("Validation failed"); this.name = "ValidationError"; } }

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

python-refactor

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

async-python-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

python-comments

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

python-packaging

No summary provided by upstream source.

Repository SourceNeeds Review