agentleFS
NembieNembie/claude-code-skills/skills/typescript-refactorer/SKILL.md

typescript-refactorer

Skill3 starsChanged 9 months agoMITView on GitHub

Identify TypeScript code smells and suggest type-safe refactoring. Use when asked to refactor, improve types, clean up TypeScript code, tighten types, reduce any usage, or improve type safety.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Before generating any output, read config/defaults.md and adapt all patterns, imports, and code examples to the user's configured stack.

    line 8
  2. Distinctive:

    After suggesting refactoring changes, verify that the refactored code is type-correct by checking for: consistent type usage across the …

    line 203

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

TypeScript Refactorer

Before generating any output, read config/defaults.md and adapt all patterns, imports, and code examples to the user's configured stack.

Analysis Process

  1. Scan the specified files for type-related code smells
  2. Categorize issues by severity
  3. Provide corrected code for each issue

Code Smells to Detect

Explicit any Usage

// BAD
function process(data: any) {
  return data.value;
}

// GOOD: Use specific type or generic
function process<T extends { value: unknown }>(data: T) {
  return data.value;
}

// GOOD: Use unknown with type guard
function process(data: unknown) {
  if (isValidData(data)) {
    return data.value;
  }
  throw new Error('Invalid data');
}

Implicit any from Missing Types

// BAD: Parameter implicitly has 'any' type
function calculate(x, y) {
  return x + y;
}

// GOOD
function calculate(x: number, y: number): number {
  return x + y;
}

Unnecessary Type Assertions

// BAD: Assertion when type is already known
const value = getValue() as string; // getValue already returns string

// BAD: Double assertion (type laundering)
const data = response as unknown as User;

// GOOD: Fix the source type or use type guard
const data = isUser(response) ? response : null;

Overly Broad Union Types

// BAD
type Status = string;

// GOOD: Use literal union
type Status = 'pending' | 'active' | 'completed' | 'failed';

// BAD
type Result = { success: boolean; data?: any; error?: string };

// GOOD: Discriminated union
type Result =
  | { success: true; data: User }
  | { success: false; error: string };

Missing Discriminated Unions

// BAD: Ambiguous state
interface State {
  loading: boolean;
  data: User | null;
  error: Error | null;
}

// GOOD: Discriminated union makes invalid states unrepresentable
type State =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: User }
  | { status: 'error'; error: Error };

Implicit Return Types

// BAD: Return type inferred as complex union
function getUser(id: string) {
  if (!id) return null;
  return fetchUser(id); // Returns Promise<User>
}
// Inferred: (id: string) => null | Promise<User>

// GOOD: Explicit return type catches errors
function getUser(id: string): Promise<User | null> {
  if (!id) return Promise.resolve(null);
  return fetchUser(id);
}

Non-null Assertions (!)

// BAD: Hiding potential null issues
const name = user!.name;

// GOOD: Explicit null check
const name = user?.name ?? 'Anonymous';

// GOOD: Early return / throw
if (!user) throw new Error('User required');
const name = user.name;

Type-unsafe Object Access

// BAD
const value = obj['dynamicKey'];

// GOOD: Use Record type
const obj: Record<string, number> = {};
const value = obj['dynamicKey']; // value: number | undefined

// BETTER: Use Map for dynamic keys
const map = new Map<string, number>();
const value = map.get('dynamicKey');

Missing readonly

// BAD: Mutable when shouldn't be
interface Config {
  apiUrl: string;
  timeout: number;
}

// GOOD: Immutable config
interface Config {
  readonly apiUrl: string;
  readonly timeout: number;
}

// Or use Readonly utility
type Config = Readonly<{
  apiUrl: string;
  timeout: number;
}>;

Function Overloads Instead of Unions

// BAD: Unclear relationship between input and output
function parse(input: string | Buffer): string | Uint8Array;

// GOOD: Overloads make it explicit
function parse(input: string): string;
function parse(input: Buffer): Uint8Array;
function parse(input: string | Buffer): string | Uint8Array {
  // Implementation
}

Output Format

## TypeScript Analysis

### Critical (type safety compromised)
- **Explicit any** in `src/utils/api.ts:23`
  - Issue: `data: any` parameter loses all type information
  - Fix: [code block with typed version]

### Warnings (potential issues)
- **Missing discriminated union** in `src/types/state.ts:5`
  - Issue: State type allows invalid combinations
  - Fix: [code block with discriminated union]

### Suggestions (improvements)
- **Implicit return type** in `src/services/user.ts:45`
  - Issue: Complex inferred return type
  - Fix: [code block with explicit return type]

### Summary
- Critical: X issues
- Warnings: X issues
- Suggestions: X issues

Before/After Verification

After suggesting refactoring changes, verify that the refactored code is type-correct by checking for: consistent type usage across the changed files, no introduced type errors in function signatures, all imports still valid. If a suggested refactoring would break a downstream consumer, flag it: BREAKING: this change affects [file/function] — update those references too.

Reference

See references/code-smells.md for a complete catalog of TypeScript anti-patterns.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.