Maybe Monad로 null 체크 체이닝

type Maybe<T> = T | null

const Maybe = {
  of: <T>(value: T): Maybe<T> => (value != null ? value : null),
  map: <T, U>(m: Maybe<T>, fn: (v: T) => U): Maybe<U> =>
    m != null ? Maybe.of(fn(m)) : null,
}

// 사용 예: DOM 요소 찾아서 스크롤
Maybe.of(scrollElement.current)
  .map((root) => root.querySelector(`#${id}`))
  .map((target) => target.getClientRects()[0])
  .map((rect) => {
    root.scrollLeft = rect.left
  })

Generator로 early return 패턴도 가능

function* handleScroll(id) {
  const root = scrollElement.current
  if (!root) return
  const target = root.querySelector(`#${id}`)
  if (!target) return
  yield target.getClientRects()[0]?.left ?? 0
}
#533

모나드 입문

모나드 = 복잡한 처리를 숨기면서 연속된 연산을 가능하게 하는 패턴

  1. 타입 래퍼 - 값을 감싸는 구조 (예: NumberWithLogs)
  2. 래핑 함수 (unit/return) - 값을 모나드로 감쌈
  3. 바인딩 함수 (bind/flatMap) - 래핑된 값에 함수 적용
interface NumberWithLogs {
  result: number
  logs: string[]
}

function wrapWithLogs(n: number): NumberWithLogs {
  return { result: n, logs: [] }
}

function runWithLogs(
  input: NumberWithLogs,
  transform: (n: number) => NumberWithLogs
): NumberWithLogs {
  const next = transform(input.result)
  return { result: next.result, logs: [...input.logs, ...next.logs] }
}

Option, Promise도 모나드. then이 바인딩 함수 역할.

#534

TypeScript Maybe Monad 구현

type Maybe<T> = Just<T> | Nothing

class Just<T> {
  constructor(public value: T) {}
  bind<U>(fn: (value: T) => Maybe<U>): Maybe<U> {
    return fn(this.value)
  }
}

class Nothing {
  bind<U>(fn: (value: any) => Maybe<U>): Maybe<U> {
    return this
  }
}

const nothing = new Nothing()

function safeDivide(x: number, y: number): Maybe<number> {
  return y === 0 ? nothing : new Just(x / y)
}

new Just(10).bind((x) => safeDivide(x, 2)) // Just { value: 5 }
new Just(10).bind((x) => safeDivide(x, 0)) // Nothing {}
#535

콜백 → Promise → async/await

// 콜백
fetchData(() => {
  processData(() => {
    displayData()
  })
})

// Promise 체인
fetchData().then(processData).then(displayData)

// async/await
async function main() {
  const data = await fetchData()
  const processed = await processData(data)
  await displayData(processed)
}

Promise는 모나드처럼 동작 - then이 bind/flatMap 역할

  • map: 값 변환 (중첩 허용)
  • flatMap: 값 변환 + 평탄화 (Promise의 then)
#536