---
id: wiki-2026-0508-functional-programming-in-typesc
title: Functional Programming in TypeScript
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [FP TS, fp-ts, Effect-TS, Functional TypeScript]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [typescript, functional-programming, effect-ts, fp-ts]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
  language: typescript
  framework: effect-ts
---

# Functional Programming in TypeScript

## 매 한 줄
> **"매 type system 이 매 effect 와 매 error 를 매 first-class 로 추적한다."**. Pure function + immutable + typed effect. 매 2026 의 FP-TS landscape 는 매 Effect-TS 가 매 dominant — fp-ts/io-ts 의 매 후계자.

## 매 핵심

### 매 원칙
- **Purity**: 매 같은 input → 매 같은 output. 매 side effect X.
- **Immutability**: 매 mutation X. 매 readonly + structural copy.
- **Composition**: 매 small function 의 매 pipe / flow.
- **Total functions**: 매 모든 input 에 매 정의된 output. 매 throw X — 매 Either / Effect.
- **Typed errors**: 매 error type 을 매 signature 에 매 표현.

### 매 핵심 구조
- **Option**: nullable 의 매 type-safe 표현.
- **Either**: success / failure union.
- **Effect**: 매 lazy computation + dependency + error type — `Effect<A, E, R>`.
- **Stream**: 매 lazy async iterator.
- **Schema**: 매 runtime + static type.

### 매 응용
1. API client — 매 typed error / retry / timeout 의 매 declarative.
2. Form validation — 매 Schema parse + Either.
3. Concurrent workflow — 매 Effect.all + structured concurrency.

## 💻 패턴

### Option / Either basics (Effect-TS)
```typescript
import { Option, Either } from 'effect';

const safeDiv = (a: number, b: number): Option.Option<number> =>
  b === 0 ? Option.none() : Option.some(a / b);

const parsed: Either.Either<number, string> =
  Either.try({ try: () => JSON.parse('{"x":1}').x, catch: e => String(e) });
```

### Pipe + flow
```typescript
import { pipe, flow } from 'effect';

const upper = (s: string) => s.toUpperCase();
const exclaim = (s: string) => `${s}!`;

const shout = flow(upper, exclaim);
console.log(pipe('hello', shout));  // "HELLO!"
```

### Effect with typed errors
```typescript
import { Effect } from 'effect';

class NotFoundError { readonly _tag = 'NotFoundError' }
class NetworkError  { readonly _tag = 'NetworkError'  }

const fetchUser = (id: string): Effect.Effect<User, NotFoundError | NetworkError> =>
  Effect.tryPromise({
    try: () => fetch(`/u/${id}`).then(r => {
      if (r.status === 404) throw new NotFoundError();
      return r.json();
    }),
    catch: e => e instanceof NotFoundError ? e : new NetworkError(),
  });
```

### Service / dependency injection
```typescript
import { Context, Effect, Layer } from 'effect';

class Logger extends Context.Tag('Logger')<Logger, { log: (m: string) => void }>() {}

const program = Effect.gen(function* () {
  const logger = yield* Logger;
  logger.log('hi');
});

const LoggerLive = Layer.succeed(Logger, { log: console.log });
Effect.runSync(Effect.provide(program, LoggerLive));
```

### Schema validation (runtime + static)
```typescript
import { Schema } from 'effect';

const User = Schema.Struct({
  id: Schema.String,
  age: Schema.Number.pipe(Schema.between(0, 150)),
  email: Schema.String.pipe(Schema.pattern(/^[^@]+@[^@]+$/)),
});
type User = Schema.Schema.Type<typeof User>;

const parseUser = Schema.decodeUnknownEither(User);
```

### Structured concurrency
```typescript
const fetchAll = Effect.all(
  [fetchUser('a'), fetchUser('b'), fetchUser('c')],
  { concurrency: 2 }   // limit
).pipe(
  Effect.timeout('5 seconds'),
  Effect.retry({ times: 3 }),
);
```

### Immutable update with Optic
```typescript
import { Lens } from 'monocle-ts';

interface Order { user: { name: string } }
const userName = Lens.fromPath<Order>()(['user', 'name']);
const upd = userName.modify(s => s.toUpperCase());
const next = upd({ user: { name: 'foo' } });   // structural copy
```

### Discriminated union exhaustiveness
```typescript
type Shape =
  | { kind: 'circle'; r: number }
  | { kind: 'square'; s: number };

const area = (sh: Shape): number => {
  switch (sh.kind) {
    case 'circle': return Math.PI * sh.r ** 2;
    case 'square': return sh.s ** 2;
    default: { const _: never = sh; return _; }   // compile error if missed
  }
};
```

## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 nullable | Option (or `T \| undefined` + helper) |
| 매 expected error | Either / Effect typed error |
| 매 unexpected (bug) | throw — 매 error boundary |
| 매 async + DI + retry | Effect-TS |
| 매 simple validation | Zod (lighter) |
| 매 large schema + transform | Effect Schema |

**기본값**: 매 plain TS + readonly + discriminated union. 매 복잡한 effect orchestration 은 매 Effect-TS.

## 🔗 Graph
- 부모: [[TypeScript]] · [[Functional Programming]]
- 변형: [[Effect-TS]] · [[fp-ts]]
- 응용: [[Validation]] · [[API Client]] · [[State Management]]
- Adjacent: [[Zod]]

## 🤖 LLM 활용
**언제**: 매 typed error model 설계, 매 schema-first API, 매 effect-heavy domain code.
**언제 X**: 매 simple CRUD UI — 매 overkill.

## ❌ 안티패턴
- **Effect 모든 곳**: 매 over-abstraction. 매 leaf function 은 매 plain.
- **`any` escape hatch**: 매 type 의 매 의미 손실.
- **Mutating in pipe**: 매 immutability 위반.
- **Throw inside Effect.try with rethrow**: 매 typed error 회피.

## 🧪 검증 / 중복
- Verified (Effect-TS 3.x docs, fp-ts legacy migration guide).
- 신뢰도 A.

## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 매 Effect-TS 기준 패턴 + Schema |
