
Clean Code Ts
- 3 installs
- Updated April 3, 2026
- franalgaba/clean-code-typescript
Reviews and refactors TypeScript or TSX code against Clean Code principles, producing a categorized violation report plus a refactored version.
About
Analyzes TypeScript code against a Clean Code ruleset covering variables, functions, classes, SOLID, and error handling, then reports every violation and returns refactored code. A developer uses it to review or clean up TypeScript for readability and maintainability.
- Reports violations grouped by Clean Code category with rule names
- Returns a fully refactored version of the code
Clean Code Ts by the numbers
- 3 all-time installs (skills.sh)
- Ranked #923 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Jul 24, 2026 (Skillselion catalog sync)
npx skills add https://github.com/franalgaba/clean-code-typescript --skill clean-code-tsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3 |
|---|---|
| Last updated | April 3, 2026 |
| Repository | franalgaba/clean-code-typescript ↗ |
What it does
Reviews and refactors TypeScript or TSX code against Clean Code principles, producing a categorized violation report plus a refactored version.
Files
Clean Code TypeScript — Review & Refactor Skill
You review TypeScript code against Clean Code principles and produce a structured report with the issues found plus a refactored version of the code.
Before you start
Read references/rules.md in this skill's directory. It contains the full ruleset organised by category (Variables, Functions, Objects & Data Structures, Classes, SOLID, Testing, Concurrency, Error Handling, Formatting, Comments). You need these details to give accurate, specific feedback.
Workflow
1. Receive the code — the user provides TypeScript/TSX code (inline, as a file, or via a path). 2. Analyse — walk through the code carefully and identify every Clean Code violation. For each issue note:
- Which rule is violated (use the short rule name from the reference, e.g. "Use meaningful variable names").
- Where it occurs (function, class, or line range).
- Why it matters (one sentence — connect to readability, testability, or maintainability).
3. Refactor — produce a cleaned-up version of the entire code that resolves all identified issues. Preserve the original behaviour; this is a readability refactor, not a feature change. 4. Report — output the report in the format below.
Report format
Structure the report exactly like this:
## Clean Code Review
### Summary
<One paragraph: overall impression, number of issues found, top themes.>
### Issues
#### <Category> (e.g. Variables, Functions, Classes …)
| # | Rule | Location | Issue | Severity |
|---|------|----------|-------|----------|
| 1 | <rule name> | <where> | <what's wrong & why> | 🔴 / 🟡 / 🟢 |
<Repeat table per category that has violations.>
### Refactored Code
\`\`\`ts
<full refactored code>
\`\`\`
### Key Changes
<Bulleted list of the most impactful changes and the reasoning behind them.>Severity guide:
- 🔴 High — actively harms readability or maintainability (e.g. god class, side-effect-heavy functions, ignored errors).
- 🟡 Medium — worth fixing but not blocking (e.g. missing destructuring, unclear names, flag parameters).
- 🟢 Low — style nit or minor improvement (e.g. import ordering, redundant context in names).
Principles for the refactor
When refactoring, follow these priorities (in order):
1. Preserve behaviour — never change what the code does. 2. Maximise clarity — someone unfamiliar with the codebase should be able to read the refactored code top-to-bottom and understand it. 3. Minimise surprise — don't introduce patterns or abstractions the original author clearly wasn't using unless they solve a concrete problem identified in the review. 4. Keep it proportional — if the input is a 20-line utility, don't refactor it into 5 classes. Match the complexity of the solution to the complexity of the problem.
Edge cases
- If the code is already clean: say so! Give a short "looks good" summary and optionally suggest 1–2 minor improvements. Don't manufacture issues.
- If the code is very long (>300 lines): focus the report on the most impactful issues (cap at ~15–20). Mention that additional minor issues exist and offer to cover them if the user wants.
- If the code mixes TypeScript with framework-specific patterns (React, Angular, NestJS): still apply the Clean Code rules but be aware of idiomatic framework patterns that might look like violations but aren't (e.g. Angular decorators, React hooks naming).
- If the user only wants a review (no refactor): skip the "Refactored Code" section and expand the issues table with a "Suggested Fix" column instead.
- If the user only wants a refactor (no report): skip the issues table and just return the refactored code with a brief "Key Changes" section.
🧹 Clean Code TypeScript — Claude Skill
A Claude skill that reviews and refactors TypeScript code following Clean Code principles by Robert C. Martin, adapted for TypeScript.
Paste your TypeScript code, ask for a review, and get back a structured report with every violation identified — plus a fully refactored version of your code.
What it does
When triggered, the skill:
1. Analyses your TypeScript/TSX code against 40+ Clean Code rules across 10 categories 2. Produces a report with an issues table grouped by category, severity ratings, and explanations 3. Refactors the entire code to resolve all identified issues while preserving original behaviour
Example output
## Clean Code Review
### Summary
This snippet has 8 violations across 3 categories...
### Issues
#### Variables
| # | Rule | Location | Issue | Severity |
|---|-------------------|--------------|--------------------------------|----------|
| 1 | Use searchable names | `const d = 86400000` | Magic number with no context | 🔴 |
#### Functions
| # | Rule | Location | Issue | Severity |
|---|-------------------|--------------|--------------------------------|----------|
| 2 | Don't use flags | `proc(arr, f: boolean)` | Boolean makes function do two things | 🔴 |
### Refactored Code
// ... cleaned up version
### Key Changes
- Replaced magic number with named constant
- Split flag-driven function into two focused functions
- ...Severity levels
| Icon | Level | Meaning |
|---|---|---|
| 🔴 | High | Actively harms readability or maintainability |
| 🟡 | Medium | Worth fixing but not blocking |
| 🟢 | Low | Style nit or minor improvement |
Rules covered
The skill checks against rules in these categories:
- Variables — meaningful names, searchable names, no mental mapping, no unneeded context, enums, defaults
- Functions — single responsibility, 2 or fewer args, no flags, no side effects, functional over imperative, encapsulated conditionals, no dead code
- Objects & Data Structures — getters/setters, private members, immutability, type vs interface
- Classes — small classes, high cohesion, composition over inheritance, method chaining
- SOLID — SRP, OCP, LSP, ISP, DIP
- Testing — TDD laws, F.I.R.S.T. rules, single concept per test, intention-revealing names
- Concurrency — promises over callbacks, async/await over promise chains
- Error Handling — always use Error, never ignore caught errors or rejected promises
- Formatting — consistent capitalization, caller/callee proximity, organized imports, path aliases
- Comments — self-explanatory code, no commented-out code, no journal comments, no positional markers
Full ruleset based on clean-code-typescript by labs42io.
Installation
Download the .skill file from Releases and drag it into a Claude conversation, or add it through your Claude settings.
Manual installation
Clone this repo into your Claude skills directory:
git clone https://github.com/<your-username>/clean-code-ts.git /path/to/skills/user/clean-code-tsSkill structure
clean-code-ts/
├── SKILL.md # Main skill instructions
├── README.md # This file
├── references/
│ ├── rules.md # Condensed ruleset (quick lookup)
│ └── clean-code-typescript-full.md # Complete source with all examples
└── evals/
└── evals.json # Test cases for skill validationTrigger phrases
The skill activates when you ask Claude to:
- "Review this TypeScript code"
- "Clean up this class"
- "Refactor this for readability"
- "Audit my TS code"
- "What do you think of this code?" (with TypeScript pasted)
- "Improve this TypeScript"
It does not trigger for pure formatting requests (e.g. "run Prettier"), non-TypeScript languages, or runtime debugging unrelated to code quality.
Customisation
The skill handles several edge cases out of the box:
- Already-clean code — gives a short positive summary instead of manufacturing issues
- Very long files (300+ lines) — focuses on the top 15–20 most impactful issues
- Framework-specific code (React, Angular, NestJS) — respects idiomatic patterns
- Review only — if you ask for just a review, it skips the refactored code section
- Refactor only — if you ask for just a refactor, it skips the issues table
Credits
Rules adapted from clean-code-typescript by labs42io, which itself is inspired by clean-code-javascript by Ryan McDermott, based on Robert C. Martin's *Clean Code*.
License
MIT
Clean Code TypeScript — Full Ruleset
Reference for the clean-code-ts skill. Each section maps to a category in the review report. Rules include a short name (used in the report's "Rule" column), the principle, and a Bad → Good pattern.
---
Table of Contents
1. Variables 2. Functions 3. Objects and Data Structures 4. Classes 5. SOLID 6. Testing 7. Concurrency 8. Error Handling 9. Formatting 10. Comments
---
Variables
Use meaningful variable names
Names should reveal intent. A reader should know what each variable represents without reading surrounding context.
Bad: a1, a2, a3 → Good: value, left, right
Use pronounceable variable names
If you can't say it out loud, it's a bad name.
Bad: genymdhms, pszqint → Good: generationTimestamp, recordId
Use the same vocabulary for the same type of variable
Don't use getUserInfo, getUserDetails, and getUserData when they all return the same thing. Pick one: getUser.
Use searchable names
Avoid magic numbers and unnamed constants. Extract them into named constants.
Bad: setTimeout(restart, 86400000) → Good: const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000; setTimeout(restart, MILLISECONDS_PER_DAY);
Use explanatory variables
Destructure to give meaningful names rather than using opaque keys.
Bad: for (const keyValue of users) → Good: for (const [id, user] of users)
Avoid mental mapping
Explicit is better than implicit. Don't make readers decode single-letter names.
Bad: const u = getUser() → Good: const user = getUser()
Don't add unneeded context
If the class/type already provides context, don't repeat it in property names.
Bad: car.carMake, car.carModel → Good: car.make, car.model
Use default arguments instead of short circuiting
Default parameters are cleaner than count !== undefined ? count : 10.
Bad: const loadCount = count !== undefined ? count : 10 → Good: function loadPages(count: number = 10)
Use enum to document intent
When you care about distinctness rather than exact values, use enum instead of string-based objects.
---
Functions
Function arguments (2 or fewer ideally)
More than 2 arguments makes testing combinatorially harder. Use an options object with destructuring for 3+ parameters. This also enables named parameters and makes the signature self-documenting.
Functions should do one thing
The most important rule. If a function does lookup + filter + side-effect, split it. Each function should have a single responsibility.
Bad: loop that looks up, checks active, then emails → Good: clients.filter(isActiveClient).forEach(email)
Function names should say what they do
addToDate is ambiguous — adding what? → addMonthToDate is clear.
Functions should only be one level of abstraction
Don't mix high-level orchestration with low-level details. Extract sub-operations into named functions.
Remove duplicate code
If two functions share 80% of their logic, extract the common parts. But be thoughtful — bad abstractions can be worse than duplication.
Set default objects with Object.assign or destructuring
Use spread / Object.assign / destructuring with defaults instead of manual config.x = config.x || 'default'.
Don't use flags as function parameters
A boolean parameter usually means the function does two things. Split into two functions.
Bad: createFile(name, temp: boolean) → Good: createFile(name) + createTempFile(name)
Avoid side effects (part 1)
A function that modifies external state is a side effect. Centralise side effects; keep most functions pure.
Bad: mutating a global name variable → Good: return a new value from a pure function.
Avoid side effects (part 2)
Don't mutate input arrays/objects. Return new copies instead.
Bad: cart.push(item) → Good: return [...cart, { item, date: Date.now() }]
Don't write to global functions
Never extend native prototypes (Array.prototype.diff). Use a class that extends the native instead.
Favor functional programming over imperative
Prefer map, filter, reduce over manual for loops with mutation.
Encapsulate conditionals
Extract complex boolean expressions into descriptively-named functions.
Bad: if (subscription.isTrial || account.balance > 0) → Good: if (canActivateService(subscription, account))
Avoid negative conditionals
isEmailUsed with ! is clearer than isEmailNotUsed.
Avoid conditionals (use polymorphism)
Replace switch on type with polymorphic classes. Each subclass implements its own behaviour.
Avoid type checking
Leverage TypeScript's type system instead of instanceof checks. Define a common interface method.
Don't over-optimize
Don't cache list.length in modern environments. Trust the runtime.
Remove dead code
Unused functions/imports belong in version history, not in the codebase.
Use iterators and generators
For stream-like data, generators provide lazy execution and decouple producers from consumers.
---
Objects and Data Structures
Use getters and setters
Encapsulate access to enable validation, logging, lazy loading, and future-proof the API.
Make objects have private/protected members
Use private and readonly to hide internals. Prefer constructor(private readonly radius: number) shorthand.
Prefer immutability
Use readonly, ReadonlyArray<T>, and as const assertions. Immutable data prevents unexpected mutations.
type vs. interface
Use type for unions/intersections, interface when you need extends/implements. Be consistent within a project.
---
Classes
Classes should be small
Measured by responsibility, not lines. Follow the Single Responsibility Principle.
High cohesion and low coupling
Every field should ideally be used by most methods. If a class has two distinct groups of fields used by two distinct groups of methods, split it.
Prefer composition over inheritance
Use inheritance only for true "is-a" relationships. For "has-a", compose objects.
Use method chaining
Return this from builder-style methods for expressive, fluent APIs.
---
SOLID
Single Responsibility Principle (SRP)
A class should have only one reason to change. If a class handles both auth and settings, split it.
Open/Closed Principle (OCP)
Open for extension, closed for modification. Use abstract base classes / interfaces so new behaviour can be added via new classes, not if/else chains.
Liskov Substitution Principle (LSP)
Subclasses must be usable in place of their parent without breaking correctness. Classic violation: Square extends Rectangle where setWidth breaks getArea expectations.
Interface Segregation Principle (ISP)
Clients shouldn't depend on methods they don't use. Split fat interfaces into small, focused ones.
Dependency Inversion Principle (DIP)
Depend on abstractions (interfaces), not concretions. Inject dependencies rather than instantiating them internally.
---
Testing
The three laws of TDD
1. No production code unless it makes a failing test pass. 2. Write only enough of a test to fail. 3. Write only enough production code to pass.
F.I.R.S.T. rules
Tests should be Fast, Independent, Repeatable, Self-Validating, and Timely (written before production code).
Single concept per test
One assert per unit test. Don't bundle multiple scenarios.
The name of the test should reveal its intention
Bad: it('2/29/2020') → Good: it('should handle leap year')
---
Concurrency
Prefer promises over callbacks
Callbacks cause nesting hell. Use promisify or native promises.
Async/Await over promise chains
async/await is cleaner and more readable than .then() chains.
---
Error Handling
Always use Error for throwing or rejecting
Never throw 'string' or Promise.reject('string'). Use new Error(...) for stack traces.
Consider the Result<R> | Failure<E> pattern as a type-safe alternative to exceptions.
Don't ignore caught errors
Never write an empty catch block or just console.log. Use a proper logger and handle the error.
Don't ignore rejected promises
Same principle — always handle .catch() or use try/catch with await.
---
Formatting
Use consistent capitalization
PascalCasefor classes, interfaces, types, enums.camelCasefor variables, functions, class members.UPPER_SNAKE_CASEfor constants.
Function callers and callees should be close
Keep calling functions above the functions they call. Read top-to-bottom like a newspaper.
Organize imports
Group and alphabetize: polyfills → Node builtins → external → internal → parent → sibling. Use import type for type-only imports. Remove unused imports.
Use TypeScript path aliases
Configure baseUrl and paths in tsconfig.json to avoid deep relative imports like ../../../services/UserService.
---
Comments
Prefer self-explanatory code over comments
If you need a comment to explain what code does, the code isn't clear enough. Extract into a well-named variable or function.
Bad: // Check if subscription is active + if (subscription.endDate > Date.now) → Good: const isSubscriptionActive = subscription.endDate > Date.now
Don't leave commented-out code
Delete it. Version control has history.
Don't have journal comments
No changelogs in source files. Use git log.
Avoid positional markers
No //////////////// Section //////////////// banners. Use proper code structure and IDE folding.
TODO comments
Acceptable for noting future improvements — but they are not an excuse for leaving bad code.