Robert C. Martin (Uncle Bob) TypeScript 5.x + React 19 Best Practices
Craftsmanship principles from Robert C. Martin's Clean Code (2008), re-expressed for modern TypeScript and React. Contains 61 rules across 11 categories, prioritized by cognitive cost across a code change's lifetime. Examples use TS 5.x and React 19 idioms — but the rules are about timeless principles, not specific APIs.
What Makes This Skill Different
Three things set this apart from a generic clean-code copy:
- Modern idioms as vehicle. Examples use TS 5.x (
satisfies, branded types, discriminated unions, const type parameters) and React 19 (function components, hooks, use(), Server Components where relevant). But the rule is always the principle, never the syntax.
- "When NOT to apply" is first-class. Every rule has 2-3 concrete scenarios where the principle should bend — not generic disclaimers, real situations. Loop counters can be
i. Single-use code shouldn't be DRY. Some HOCs are unavoidable.
- Meta category for principle conflicts. Category 11 names the most common tensions explicitly — DRY vs Single Responsibility, small functions vs deep modules (Ousterhout), type precision vs ergonomic APIs, tests as spec vs documentation. The mark of seniority is knowing which to bend.
When to Apply
Reference these guidelines when:
- Writing new TypeScript or React code and wanting craftsmanship feedback
- Reviewing a pull request for clarity, naming, or abstraction
- Refactoring existing code for readability or maintainability
- Designing function, hook, or component APIs
- Deciding whether to extract, abstract, or duplicate
- Resolving a tension between two clean-code rules (see Category 11)
Skip this skill and use:
react for React 19 API patterns (concurrent rendering, Server Components, ref-as-prop, useActionState, <Context>-as-provider)
typescript for compiler performance, tsconfig tuning, type-system perf
refactor for mechanical refactoring workflows
tdd for the TDD workflow itself
Rule Categories by Priority
Order reflects cognitive cost across a change's lifetime (read → understand → modify → verify → ship → maintain). Earlier stages cascade — bad names taint every read.
| Priority |
Category |
Impact |
Prefix |
Rules |
| 1 |
Meaningful Names |
CRITICAL |
name- |
8 |
| 2 |
Functions, Components & Hooks |
CRITICAL |
func- |
8 |
| 3 |
Self-Documentation (Types & Comments) |
HIGH |
doc- |
5 |
| 4 |
Formatting (Beyond Prettier) |
HIGH |
fmt- |
4 |
| 5 |
Error Handling |
HIGH |
err- |
7 |
| 6 |
Data Shape & Immutability |
MEDIUM-HIGH |
data- |
6 |
| 7 |
Boundaries |
MEDIUM-HIGH |
bound- |
4 |
| 8 |
Composition over Inheritance |
MEDIUM-HIGH |
comp- |
6 |
| 9 |
Tests |
MEDIUM |
test- |
5 |
| 10 |
Emergence & Simple Design |
MEDIUM |
emerge- |
4 |
| 11 |
Meta: When Principles Conflict |
MEDIUM |
meta- |
4 |
Total: 61 rules.
Quick Reference
1. Meaningful Names (CRITICAL)
name-intention-revealing — Use names that reveal intent
name-avoid-disinformation — Avoid misleading names
name-meaningful-distinctions — Make meaningful distinctions
name-component-pascal-case — Components are PascalCase noun phrases
name-hook-use-prefix — Hooks are useX verb phrases
name-handler-convention — Event handlers use onX / handleX
name-boolean-predicate — Boolean variables use is/has/can
name-types-pascal-case — Types and interfaces are PascalCase
2. Functions, Components & Hooks (CRITICAL)
func-small — Keep functions, components & hooks small
func-one-thing — Do one thing
func-abstraction-level — One level of abstraction per function
func-minimize-arguments — Prefer object parameters over long lists
func-no-side-effects — Avoid hidden side effects (especially in render)
func-command-query-separation — Separate commands from queries
func-dry — DRY — until concepts diverge
func-custom-hook-extract — Extract custom hooks for reusable stateful logic
3. Self-Documentation: Types & Comments (HIGH)
doc-types-over-comments — Prefer types over comments
doc-satisfies-narrows-with-check — Use satisfies for inferred-but-checked values
doc-jsdoc-public-api — JSDoc for public APIs and non-obvious side effects
doc-avoid-redundant-comments — Avoid redundant comments
doc-delete-commented-out-code — Delete commented-out code
4. Formatting Beyond Prettier (HIGH)
fmt-vertical-density — Keep related code close, unrelated far
fmt-newspaper-order — Order files top-down like a newspaper
fmt-team-rules-over-preference — Team conventions over personal preference
fmt-imports-grouped — Group imports by source
5. Error Handling (HIGH)
err-early-return — Use early returns to flatten error paths
err-result-vs-throw — Choose throw vs Result deliberately
err-narrow-unknown — Always narrow unknown in catch blocks
err-error-boundaries — Use error boundaries for render-time failures
err-suspense-for-loading — Use Suspense for loading states
err-no-swallow — Never swallow errors silently
err-null-vs-undefined — Pick null OR undefined per domain
6. Data Shape & Immutability (MEDIUM-HIGH)
data-discriminated-unions-over-flags — Discriminated unions over boolean flags
data-readonly-by-default — Mark read-only data readonly
data-branded-types — Brand types for domain invariants
data-dto-vs-domain — Separate DTOs from domain types
data-demeter-prop-drilling — Prop drilling often smells like Demeter
data-structural-typing-pitfalls — Beware structural typing aliasing
7. Boundaries (MEDIUM-HIGH)
bound-wrap-third-party-hooks — Wrap third-party hooks in custom hooks
bound-learning-tests — Write learning tests for third-party behavior
bound-isolate-framework — Isolate framework-specific code at the edges
bound-type-assertions-at-edges — Type assertions belong only at boundaries
8. Composition over Inheritance (MEDIUM-HIGH)
comp-children-over-props — Compose with children over configuration props
comp-small-components — Keep components small and cohesive
comp-avoid-hoc-stacks — Avoid higher-order component stacks
comp-context-only-when-needed — Context for DI, not prop avoidance
comp-render-props-vs-hooks — Prefer hooks over render props for logic reuse
comp-separate-construction-from-use — Separate setup from rendering
9. Tests (MEDIUM)
test-behavior-not-implementation — Test behavior, not implementation
test-mock-at-boundaries — Mock only at true boundaries
test-first-principles — Apply FIRST principles
test-one-concept — One concept (not one assert) per test
test-clean-as-production — Test code deserves production-grade care
10. Emergence & Simple Design (MEDIUM)
emerge-four-rules — Apply the four rules of simple design in order
emerge-yagni-types — Avoid premature type generics
emerge-premature-abstraction — Resist premature abstraction
emerge-reveal-intent — Maximize expressiveness — code as communication
11. Meta: When Principles Conflict (MEDIUM)
This is the signature category — explicit guidance on when one clean-code principle yields to another.
meta-dry-vs-srp — Bend DRY when concepts drift apart
meta-small-vs-deep — Small functions lose to deep modules when indirection > comprehension
meta-types-vs-ergonomics — Type safety loses to ergonomics at stable boundaries
meta-tests-as-spec-vs-doc — Pick tests-as-spec or tests-as-documentation per file
How to Use
For an ad-hoc question ("is this naming OK?", "should I extract this?"), jump straight to the relevant rule file via the Quick Reference above.
For a code review or refactor, scan the categories in priority order — names and function shape first (highest cascade), then errors and data shape, then composition and tests. The category-major sweep is more efficient than file-major.
When two principles seem to disagree, read the corresponding Meta rule (Category 11). Pick the principle that wins, and document the call.
Reference Files
| File |
Description |
| references/_sections.md |
Category definitions and ordering |
| assets/templates/_template.md |
Template for adding new rules |
| metadata.json |
Version and reference information |
Related Skills
.experimental/clean-code — Original language-agnostic clean code (Java examples). This skill is the TS+React sibling.
.curated/react — React 19-specific patterns (Server Components, concurrent rendering, ref-as-prop).
.curated/typescript — TS compiler performance and tsconfig tuning.
.curated/refactor — Mechanical refactoring workflows.
.curated/tdd — The TDD workflow itself.
1---2name: clean-code-ts-react3description: Use when writing, reviewing, or refactoring TypeScript or React code for craftsmanship — naming, function and component shape, error handling, data modeling, tests, and abstraction. Translates Robert C. Martin's Clean Code principles into modern TS+React idioms (TS 5.x, React 19), with first-class "When NOT to apply" guidance and a Meta category for principle conflicts (DRY vs SRP, small functions vs deep modules, type safety vs ergonomics). Triggers on code review, refactoring for clarity, naming, function/component design, "is this clean?", "make this more readable", "right abstraction?" — even when the user doesn't say "clean code". Does NOT cover React-specific APIs (RSC, hooks API surface) — use the `react` skill. Does NOT cover TS compiler perf or tsconfig — use the `typescript` skill.4---5
6# Robert C. Martin (Uncle Bob) TypeScript 5.x + React 19 Best Practices
7
8Craftsmanship principles from Robert C. Martin's *Clean Code* (2008), re-expressed for modern TypeScript and React. Contains **61 rules across 11 categories**, prioritized by cognitive cost across a code change's lifetime. Examples use TS 5.x and React 19 idioms — but the rules are about timeless principles, not specific APIs.
9
10## What Makes This Skill Different
11
12Three things set this apart from a generic clean-code copy:
13
141. **Modern idioms as vehicle.** Examples use TS 5.x (`satisfies`, branded types, discriminated unions, `const` type parameters) and React 19 (function components, hooks, `use()`, Server Components where relevant). But the rule is always the principle, never the syntax.
152. **"When NOT to apply" is first-class.** Every rule has 2-3 concrete scenarios where the principle should bend — not generic disclaimers, real situations. Loop counters can be `i`. Single-use code shouldn't be DRY. Some HOCs are unavoidable.
163. **Meta category for principle conflicts.** Category 11 names the most common tensions explicitly — DRY vs Single Responsibility, small functions vs deep modules (Ousterhout), type precision vs ergonomic APIs, tests as spec vs documentation. The mark of seniority is knowing which to bend.
17
18## When to Apply
19
20Reference these guidelines when:
21- Writing new TypeScript or React code and wanting craftsmanship feedback
22- Reviewing a pull request for clarity, naming, or abstraction
23- Refactoring existing code for readability or maintainability
24- Designing function, hook, or component APIs
25- Deciding whether to extract, abstract, or duplicate
26- Resolving a tension between two clean-code rules (see Category 11)
27
28Skip this skill and use:
29- **`react`** for React 19 API patterns (concurrent rendering, Server Components, ref-as-prop, `useActionState`, `<Context>`-as-provider)
30- **`typescript`** for compiler performance, tsconfig tuning, type-system perf
31- **`refactor`** for mechanical refactoring workflows
32- **`tdd`** for the TDD workflow itself
33
34## Rule Categories by Priority
35
36Order reflects **cognitive cost across a change's lifetime** (read → understand → modify → verify → ship → maintain). Earlier stages cascade — bad names taint every read.
37
38| Priority | Category | Impact | Prefix | Rules |
39|----------|----------|--------|--------|-------|
40| 1 | Meaningful Names | CRITICAL | `name-` | 8 |
41| 2 | Functions, Components & Hooks | CRITICAL | `func-` | 8 |
42| 3 | Self-Documentation (Types & Comments) | HIGH | `doc-` | 5 |
43| 4 | Formatting (Beyond Prettier) | HIGH | `fmt-` | 4 |
44| 5 | Error Handling | HIGH | `err-` | 7 |
45| 6 | Data Shape & Immutability | MEDIUM-HIGH | `data-` | 6 |
46| 7 | Boundaries | MEDIUM-HIGH | `bound-` | 4 |
47| 8 | Composition over Inheritance | MEDIUM-HIGH | `comp-` | 6 |
48| 9 | Tests | MEDIUM | `test-` | 5 |
49| 10 | Emergence & Simple Design | MEDIUM | `emerge-` | 4 |
50| 11 | **Meta: When Principles Conflict** | MEDIUM | `meta-` | 4 |
51
52**Total: 61 rules.**
53
54## Quick Reference
55
56### 1. Meaningful Names (CRITICAL)
57
58- [`name-intention-revealing`](references/name-intention-revealing.md) — Use names that reveal intent
59- [`name-avoid-disinformation`](references/name-avoid-disinformation.md) — Avoid misleading names
60- [`name-meaningful-distinctions`](references/name-meaningful-distinctions.md) — Make meaningful distinctions
61- [`name-component-pascal-case`](references/name-component-pascal-case.md) — Components are PascalCase noun phrases
62- [`name-hook-use-prefix`](references/name-hook-use-prefix.md) — Hooks are `useX` verb phrases
63- [`name-handler-convention`](references/name-handler-convention.md) — Event handlers use `onX` / `handleX`
64- [`name-boolean-predicate`](references/name-boolean-predicate.md) — Boolean variables use `is`/`has`/`can`
65- [`name-types-pascal-case`](references/name-types-pascal-case.md) — Types and interfaces are PascalCase
66
67### 2. Functions, Components & Hooks (CRITICAL)
68
69- [`func-small`](references/func-small.md) — Keep functions, components & hooks small
70- [`func-one-thing`](references/func-one-thing.md) — Do one thing
71- [`func-abstraction-level`](references/func-abstraction-level.md) — One level of abstraction per function
72- [`func-minimize-arguments`](references/func-minimize-arguments.md) — Prefer object parameters over long lists
73- [`func-no-side-effects`](references/func-no-side-effects.md) — Avoid hidden side effects (especially in render)
74- [`func-command-query-separation`](references/func-command-query-separation.md) — Separate commands from queries
75- [`func-dry`](references/func-dry.md) — DRY — until concepts diverge
76- [`func-custom-hook-extract`](references/func-custom-hook-extract.md) — Extract custom hooks for reusable stateful logic
77
78### 3. Self-Documentation: Types & Comments (HIGH)
79
80- [`doc-types-over-comments`](references/doc-types-over-comments.md) — Prefer types over comments
81- [`doc-satisfies-narrows-with-check`](references/doc-satisfies-narrows-with-check.md) — Use `satisfies` for inferred-but-checked values
82- [`doc-jsdoc-public-api`](references/doc-jsdoc-public-api.md) — JSDoc for public APIs and non-obvious side effects
83- [`doc-avoid-redundant-comments`](references/doc-avoid-redundant-comments.md) — Avoid redundant comments
84- [`doc-delete-commented-out-code`](references/doc-delete-commented-out-code.md) — Delete commented-out code
85
86### 4. Formatting Beyond Prettier (HIGH)
87
88- [`fmt-vertical-density`](references/fmt-vertical-density.md) — Keep related code close, unrelated far
89- [`fmt-newspaper-order`](references/fmt-newspaper-order.md) — Order files top-down like a newspaper
90- [`fmt-team-rules-over-preference`](references/fmt-team-rules-over-preference.md) — Team conventions over personal preference
91- [`fmt-imports-grouped`](references/fmt-imports-grouped.md) — Group imports by source
92
93### 5. Error Handling (HIGH)
94
95- [`err-early-return`](references/err-early-return.md) — Use early returns to flatten error paths
96- [`err-result-vs-throw`](references/err-result-vs-throw.md) — Choose throw vs Result deliberately
97- [`err-narrow-unknown`](references/err-narrow-unknown.md) — Always narrow `unknown` in catch blocks
98- [`err-error-boundaries`](references/err-error-boundaries.md) — Use error boundaries for render-time failures
99- [`err-suspense-for-loading`](references/err-suspense-for-loading.md) — Use Suspense for loading states
100- [`err-no-swallow`](references/err-no-swallow.md) — Never swallow errors silently
101- [`err-null-vs-undefined`](references/err-null-vs-undefined.md) — Pick `null` OR `undefined` per domain
102
103### 6. Data Shape & Immutability (MEDIUM-HIGH)
104
105- [`data-discriminated-unions-over-flags`](references/data-discriminated-unions-over-flags.md) — Discriminated unions over boolean flags
106- [`data-readonly-by-default`](references/data-readonly-by-default.md) — Mark read-only data `readonly`
107- [`data-branded-types`](references/data-branded-types.md) — Brand types for domain invariants
108- [`data-dto-vs-domain`](references/data-dto-vs-domain.md) — Separate DTOs from domain types
109- [`data-demeter-prop-drilling`](references/data-demeter-prop-drilling.md) — Prop drilling often smells like Demeter
110- [`data-structural-typing-pitfalls`](references/data-structural-typing-pitfalls.md) — Beware structural typing aliasing
111
112### 7. Boundaries (MEDIUM-HIGH)
113
114- [`bound-wrap-third-party-hooks`](references/bound-wrap-third-party-hooks.md) — Wrap third-party hooks in custom hooks
115- [`bound-learning-tests`](references/bound-learning-tests.md) — Write learning tests for third-party behavior
116- [`bound-isolate-framework`](references/bound-isolate-framework.md) — Isolate framework-specific code at the edges
117- [`bound-type-assertions-at-edges`](references/bound-type-assertions-at-edges.md) — Type assertions belong only at boundaries
118
119### 8. Composition over Inheritance (MEDIUM-HIGH)
120
121- [`comp-children-over-props`](references/comp-children-over-props.md) — Compose with `children` over configuration props
122- [`comp-small-components`](references/comp-small-components.md) — Keep components small and cohesive
123- [`comp-avoid-hoc-stacks`](references/comp-avoid-hoc-stacks.md) — Avoid higher-order component stacks
124- [`comp-context-only-when-needed`](references/comp-context-only-when-needed.md) — Context for DI, not prop avoidance
125- [`comp-render-props-vs-hooks`](references/comp-render-props-vs-hooks.md) — Prefer hooks over render props for logic reuse
126- [`comp-separate-construction-from-use`](references/comp-separate-construction-from-use.md) — Separate setup from rendering
127
128### 9. Tests (MEDIUM)
129
130- [`test-behavior-not-implementation`](references/test-behavior-not-implementation.md) — Test behavior, not implementation
131- [`test-mock-at-boundaries`](references/test-mock-at-boundaries.md) — Mock only at true boundaries
132- [`test-first-principles`](references/test-first-principles.md) — Apply FIRST principles
133- [`test-one-concept`](references/test-one-concept.md) — One concept (not one assert) per test
134- [`test-clean-as-production`](references/test-clean-as-production.md) — Test code deserves production-grade care
135
136### 10. Emergence & Simple Design (MEDIUM)
137
138- [`emerge-four-rules`](references/emerge-four-rules.md) — Apply the four rules of simple design in order
139- [`emerge-yagni-types`](references/emerge-yagni-types.md) — Avoid premature type generics
140- [`emerge-premature-abstraction`](references/emerge-premature-abstraction.md) — Resist premature abstraction
141- [`emerge-reveal-intent`](references/emerge-reveal-intent.md) — Maximize expressiveness — code as communication
142
143### 11. Meta: When Principles Conflict (MEDIUM)
144
145**This is the signature category** — explicit guidance on when one clean-code principle yields to another.
146
147- [`meta-dry-vs-srp`](references/meta-dry-vs-srp.md) — Bend DRY when concepts drift apart
148- [`meta-small-vs-deep`](references/meta-small-vs-deep.md) — Small functions lose to deep modules when indirection > comprehension
149- [`meta-types-vs-ergonomics`](references/meta-types-vs-ergonomics.md) — Type safety loses to ergonomics at stable boundaries
150- [`meta-tests-as-spec-vs-doc`](references/meta-tests-as-spec-vs-doc.md) — Pick tests-as-spec or tests-as-documentation per file
151
152## How to Use
153
154For an ad-hoc question ("is this naming OK?", "should I extract this?"), jump straight to the relevant rule file via the Quick Reference above.
155
156For a code review or refactor, scan the categories in priority order — names and function shape first (highest cascade), then errors and data shape, then composition and tests. The category-major sweep is more efficient than file-major.
157
158When two principles seem to disagree, read the corresponding Meta rule (Category 11). Pick the principle that wins, and document the call.
159
160## Reference Files
161
162| File | Description |
163|------|-------------|
164| [references/_sections.md](references/_sections.md) | Category definitions and ordering |
165| [assets/templates/_template.md](assets/templates/_template.md) | Template for adding new rules |
166| [metadata.json](metadata.json) | Version and reference information |
167
168## Related Skills
169
170- `.experimental/clean-code` — Original language-agnostic clean code (Java examples). This skill is the TS+React sibling.
171- `.curated/react` — React 19-specific patterns (Server Components, concurrent rendering, ref-as-prop).
172- `.curated/typescript` — TS compiler performance and tsconfig tuning.
173- `.curated/refactor` — Mechanical refactoring workflows.
174- `.curated/tdd` — The TDD workflow itself.