ACTIVATE when the user wants to refactor, redesign, extract classes/value objects, or restructure TypeScript code. ACTIVATE for 'refactor', 'extract', 'redesign', 'simplify', 'clean up'. Covers: mandatory end-to-end flow analysis before refactoring, consumer-driven value object design, imports as coupling signals, value object completeness checklist. DO NOT use for: writing new features, general OOP patterns (see ts-oop).
From typescriptnpx claudepluginhub fabiensalles/claude-marketplace --plugin typescriptThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Implements structured self-debugging workflow for AI agent failures: capture errors, diagnose patterns like loops or context overflow, apply contained recoveries, and generate introspection reports.
Before touching the code, trace the data flow end-to-end. A local refactoring that ignores the global flow produces incomplete abstractions.
// ❌ AVOID - Refactoring a controller without understanding the complete flow
// We create an UploadFile in the controller...
const uploadFile = new UploadFile(content, fileName);
// ...but we haven't seen that the same object is also created
// in downloadExistingFiles() with different data.
// Result: two inconsistent creation paths.
// ✅ CORRECT - Trace the complete flow BEFORE refactoring
//
// 1. Identify all inputs: form, API, database
// 2. Trace each piece of data from source to final destination
// 3. Spot convergence points (same object, different sources)
// 4. Design the abstraction that covers ALL paths
//
// Example: UploadFile is created from:
// - an uploaded file (form → File → UploadFile)
// - an existing file re-downloaded (API → binary content → UploadFile)
// → The abstraction must unify both sources
Criterion: if an object can be constructed from N different sources, the refactoring must identify all of them before defining the structure.
When creating or modifying a value object, list all its consumers to define the necessary properties. Don't limit yourself to the creation point.
// ❌ AVOID - Defining a value object only from its creation point
class UploadFile {
constructor(
readonly content: Buffer,
readonly originalFileName: string,
) {}
}
// Later, a consumer needs the file type...
// We discover a missing property.
// The consumer must maintain an external mapping.
// ✅ CORRECT - Analyze consumers before defining the structure
//
// Steps:
// 1. List all places that CONSUME the object
// 2. For each consumer, note the data it needs
// 3. Include in the object everything consumers extract
//
// Consumer: repository.upload(file, request)
// → needs file.content, file.originalFileName
// → needs request.fileType (comes from the file)
//
// → The type must be carried by UploadFile itself
class UploadFile {
constructor(
readonly type: FileType,
readonly content: Buffer,
readonly originalFileName: string,
) {}
}
Criterion: a value object is complete when no consumer needs an external mapping to interpret it.
A file's imports reveal its actual dependencies. After a refactoring, verify that remaining imports are consistent with the class's responsibility.
// ❌ AVOID - A service that imports infrastructure types
import { Request, Response } from 'express';
import { PrismaClient } from '@prisma/client';
// This domain service manipulates HTTP and DB types directly.
// The imports betray a leaky abstraction.
// ✅ CORRECT - Imports reflect the right abstraction level
import { UploadFile } from '../domain/upload-file';
import { TenantRepository } from '../domain/ports/tenant-repository';
// The service only manipulates domain objects.
// The conversion from HTTP/DB types is done at the boundaries.
//
// Post-refactoring verification:
// 1. List the file's imports
// 2. Does each import belong to this class's responsibility?
// 3. A "foreign" import signals misplaced responsibility
Criterion: after a refactoring, if a file imports a type that doesn't match its layer/responsibility, it signals that code should be moved.
A value object is complete when it carries all information its consumers need, without requiring them to look it up elsewhere.
See also:
ts-ooprule #5 (Self-Descriptive Value Objects) for the pattern.
| Rule | Principle |
|---|---|
| Complete business flow | Trace all sources and destinations before refactoring |
| Trace consumers | List all usages to define a value object's structure |
| Imports = coupling | Imports reveal dependencies; verify their coherence |
| Complete value objects | Include everything consumers need, no external mappings |