AgentSkillsCN

js-ts-fp

以函数式编程原则,像顶级工程师一样编写 TypeScript 和 JavaScript 代码。当您需要编写新代码、审查现有代码,或重构 TS/JS 项目时,可使用此技能。坚持使用纯函数、不可变性、函数组合、高阶函数、声明式风格,并仅依靠原生模式避免共享状态(无需引入外部库)。在做出任何改动或提出改进建议之前,务必先分析现有代码库,深入了解其中的模式与惯例。

SKILL.md
--- frontmatter
name: js-ts-fp
description: Write TypeScript and JavaScript code like a top engineer using functional programming principles. Use when writing new code, reviewing existing code, or refactoring TS/JS projects. Applies pure functions, immutability, function composition, higher-order functions, declarative style, and avoiding shared state using native patterns only (no external libraries). Always analyzes the existing codebase first to understand patterns and conventions before making changes or suggestions.

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:

  1. Confirm TypeScript or JavaScript: Check for .ts, .tsx, .js, .jsx files and package.json
  2. Find existing patterns: Look at 2-3 representative files to understand current conventions
  3. 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):

PrincipleDescription
Pure functionsNo side effects, same input → same output
ImmutabilityNever mutate, always return new values
Declarative styleDescribe what, not how
Function compositionBuild complex from simple functions
Higher-order functionsFunctions that take/return functions
Avoid shared stateNo globals, no mutation of external state
Discriminated unionsTypeScript 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

code
// 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

code
// 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

code
// Before: shared state
let counter = 0;
function increment() {
  counter++;
  return counter;
}

// After: pure
function increment(counter) {
  return counter + 1;
}

Nested Logic → Composition

code
// 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-PatternRefactor To
for loop with pushmap/filter/reduce
let with reassignmentconst with transformation
Nested callbacksComposition or async/await
null checks everywhereOption/Maybe type
try/catch everywhereResult/Either type
Class with mutable statePure functions + data
Global variablesDependency injection
if/else chainsPattern 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