js-ts-fp
Functional Programming Engineering Skill
Write and review code using functional programming principles like a top engineer.
Workflow
Step 1: Analyze the Codebase
Before writing or reviewing any code, examine the repository:
- Confirm TypeScript or JavaScript: Check for
.ts,.tsx,.js,.jsxfiles andpackage.json - Find existing patterns: Look at 2-3 representative files to understand current conventions
- Check tsconfig.json: Note strict mode, module system, and target ES version
Step 2: Apply FP Principles
Apply these principles (all natively supported in TS/JS):
| Principle | Description |
|---|---|
| Pure functions | No side effects, same input → same output |
| Immutability | Never mutate, always return new values |
| Declarative style | Describe what, not how |
| Function composition | Build complex from simple functions |
| Higher-order functions | Functions that take/return functions |
| Avoid shared state | No globals, no mutation of external state |
| Discriminated unions | TypeScript pattern matching alternative |
Step 3: Execute Task
Writing new code:
- Follow existing repo conventions for file structure and naming
- Use FP patterns consistent with what's already in the codebase
- If no FP patterns exist, introduce them gradually and idiomatically
Reviewing code:
- Identify imperative patterns that could be functional
- Flag mutation, side effects, shared state
- Suggest specific refactors with before/after examples
Refactoring:
- Preserve behavior while improving structure
- Transform loops → map/filter/reduce
- Extract pure functions from impure ones
- Isolate side effects to boundaries
Core FP Transformations
Imperative → Declarative
// Before: imperative loop
let results = [];
for (let i = 0; i < items.length; i++) {
if (items[i].active) {
results.push(transform(items[i]));
}
}
// After: declarative
const results = items
.filter(item => item.active)
.map(transform);
Mutation → Immutability
// Before: mutation
function addItem(cart, item) {
cart.items.push(item);
cart.total += item.price;
return cart;
}
// After: immutable
function addItem(cart, item) {
return {
...cart,
items: [...cart.items, item],
total: cart.total + item.price
};
}
Shared State → Pure Functions
// Before: shared state
let counter = 0;
function increment() {
counter++;
return counter;
}
// After: pure
function increment(counter) {
return counter + 1;
}
Nested Logic → Composition
// Before: nested
function process(data) {
const validated = validate(data);
if (validated) {
const transformed = transform(validated);
return format(transformed);
}
return null;
}
// After: composed (with pipe/flow)
const process = pipe(
validate,
transform,
format
);
Detailed Patterns Reference
For comprehensive patterns including Option/Result types, composition helpers, currying, and TypeScript-specific techniques, see references/patterns.md.
Code Review Checklist
When reviewing, check for:
- Functions return values (not void/undefined for logic)
- No mutation of input parameters
- Side effects isolated and clearly marked
- Loops replaced with map/filter/reduce where clearer
- Conditionals use early returns or ternaries for simple cases
- Complex conditionals extracted to named predicates
- State transformations are pure
- Error handling uses Result/Either/Option patterns when available
Anti-Patterns to Flag
| Anti-Pattern | Refactor To |
|---|---|
for loop with push |
map/filter/reduce |
let with reassignment |
const with transformation |
| Nested callbacks | Composition or async/await |
null checks everywhere |
Option/Maybe type |
try/catch everywhere |
Result/Either type |
| Class with mutable state | Pure functions + data |
| Global variables | Dependency injection |
if/else chains |
Pattern matching or lookup tables |
When NOT to Apply FP
- Performance-critical hot paths where mutation is measurably faster
- When the team/codebase has no FP experience (introduce gradually)
- Simple scripts where FP adds complexity without benefit
- When existing patterns in the repo are intentionally imperative
- Legacy codebases where consistency matters more than FP purity
More from adibfirman/dotfiles
deslop-simplify-ai-code
>
25react-native-best-practices
Provides React Native performance optimization guidelines for FPS, TTI, bundle size, memory leaks, re-renders, and animations. Applies to tasks involving Hermes optimization, JS thread blocking, bridge overhead, FlashList, native modules, or debugging jank and frame drops.
20ui-engineer
Act as a UI engineer to iterate on design details and produce production-grade frontend interfaces. Use when the user provides a PRD (Product Requirements Document) or an existing concept app and wants to refine the UI through clarifying questions before implementation. Outputs HTML/CSS with Tailwind, optional vanilla JS. Focuses on minimalist aesthetics, semi-bold typography, responsive design, and avoids generic AI look, excessive icons, or emojis.
14grill-me
Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to stress-test a plan, get grilled on their design, or mentions "grill me".
1golang-samber-hot
In-memory caching in Golang using samber/hot — eviction algorithms (LRU, LFU, TinyLFU, W-TinyLFU, S3FIFO, ARC, TwoQueue, SIEVE, FIFO), TTL, cache loaders, sharding, stale-while-revalidate, missing key caching, and Prometheus metrics. Apply when using or adopting samber/hot, when the codebase imports github.com/samber/hot, or when the project repeatedly loads the same medium-to-low cardinality resources at high frequency and needs to reduce latency or backend pressure.
1context7-mcp
This skill should be used when the user asks about libraries, frameworks, API references, or needs code examples. Activates for setup questions, code generation involving libraries, or mentions of specific frameworks like React, Vue, Next.js, Prisma, Supabase, etc.
1