Files
2nd/10_Wiki/Topics/Coding/Null_Safety_Patterns.md
T
2026-05-09 21:08:02 +09:00

5.3 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, created_at, updated_at, last_reinforced, review_reason, merge_history, tags, raw_sources, tech_stack, applied_in
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status created_at updated_at last_reinforced review_reason merge_history tags raw_sources tech_stack applied_in
null-safety-patterns Null 안전 패턴 (Null Safety Patterns) Coding draft null-safety-patterns
optional
maybe
nullable
undefined-handling
NPE
null B 0.85 conceptual 2026-05-09 2026-05-09 2026-05-09
coding
type-safety
null
undefined
vibe-coding
P-Reinforce session 2026-05-09 — bulk Coding seed batch 1
language applicable_to
TypeScript / Kotlin / Rust / Swift
모든 도메인

Null 안전 패턴

Null/undefined 는 "값이 없음"이라는 정보를 담지 못하는 가장 빈약한 표현. 타입에서 nullable 을 명시적으로 분리하고, 언래핑 지점을 명확히 만들어라.

📖 핵심 개념

Tony Hoare가 "the billion dollar mistake" 라고 부른 null 참조 문제. 모던 언어들은 다음 중 하나로 대응:

  1. 타입 시스템에서 nullable 분리: TypeScript T | null, Kotlin T?, Swift T?
  2. Optional 타입: Rust Option<T>, Haskell Maybe a
  3. Strict mode: TS의 strictNullChecks, Kotlin 디폴트, Swift 디폴트

핵심은 "이 값은 없을 수 있다"를 타입이 명시적으로 표현하고 컴파일러가 강제하는 것.

💻 코드 패턴

1. nullable 명시 (TypeScript with strictNullChecks)

// ❌ 모호함 — name 이 항상 있는지 가끔 없는지 모름
function greet(user: { name: string }) { return `Hi, ${user.name}`; }

// ✅ 명시
function greet(user: { name: string | null }) {
  if (user.name === null) return 'Hi, friend';
  return `Hi, ${user.name}`;
}

2. Optional Chaining + Nullish Coalescing

// 깊은 경로 안전 접근
const city = order?.shipping?.address?.city ?? 'Unknown';

// ❌ 주의: || 는 falsy("" / 0) 도 fallback 으로 처리
const port = config.port || 3000; // port가 0이면 3000 됨!
const port = config.port ?? 3000; // null/undefined 만 fallback ✓

3. 타입 가드 + 좁히기

function isPresent<T>(x: T | null | undefined): x is T {
  return x !== null && x !== undefined;
}

const items = users.map(u => u.email).filter(isPresent); // string[]

4. Maybe / Option 모나드 패턴 (TS)

type Some<T> = { kind: 'some'; value: T };
type None = { kind: 'none' };
type Maybe<T> = Some<T> | None;

const some = <T>(value: T): Maybe<T> => ({ kind: 'some', value });
const none = (): Maybe<never> => ({ kind: 'none' });

function map<T, U>(m: Maybe<T>, f: (t: T) => U): Maybe<U> {
  return m.kind === 'none' ? m : some(f(m.value));
}
function getOr<T>(m: Maybe<T>, fallback: T): T {
  return m.kind === 'some' ? m.value : fallback;
}

복잡한 변환 체인이 많을 때만 도입. 단순한 T | null 로 충분한 경우엔 over-engineering.

5. Non-null assertion (!) 의 좁은 사용

const el = document.getElementById('root')!; // OK if you control the HTML

// ❌ 위험
function findUser(id: string) {
  return users.find(u => u.id === id)!; // 못 찾으면 런타임 사고
}

// ✅
function findUser(id: string): User {
  const u = users.find(u => u.id === id);
  if (!u) throw new NotFoundError(id);
  return u;
}

🤔 의사결정 기준

시그니처 의미 사용 시점
T 항상 값 있음 강한 보장이 필요할 때 (도메인 invariant)
T | null 값이 의도적으로 없을 수 있음 "선택 사항" 의미 명확할 때
T | undefined 아직 초기화 안 됨 / 키 없음 object property optional 표현
T | null | undefined 둘 다 가능 외부 데이터 (API 응답) — 즉시 정규화 권장
Maybe<T> / Option<T> 변환 체이닝이 잦음 복잡한 nullable pipeline

안티패턴

  • any 로 회피: 타입 시스템 우회. 컴파일은 통과하지만 런타임 폭사.
  • Non-null assertion 남발 (x!.y!.z!): 컴파일러를 침묵시키지만 보장 없음. 매번 가드 또는 스키마 검증.
  • || 로 falsy 까지 fallback: 0, "", false 가 의미 있는 값일 때 사고. ?? 사용.
  • null 과 undefined 둘 다 보내기: 한 코드베이스에서 한 컨벤션 (보통 undefined 권장 — JSON 직렬화 시 사라져 명시적).
  • null check 잊고 nested access: obj.a.b.cobj.a null 일 때 폭사. optional chaining ?. 사용.
  • 외부 API 응답을 그대로 nullable 채로 도메인 깊숙이 전파: 경계에서 zod / io-ts 같은 스키마로 정규화.

🤖 LLM 활용 힌트

  • LLM에게 함수 작성: "strictNullChecks 가정. 가능한 nullable 은 시그니처에 명시" 라고 요청.
  • 외부 API 파싱: "zod 같은 라이브러리로 nullable 을 즉시 도메인 타입으로 정규화" 명시.
  • TypeScript 옵션: 프로젝트 tsconfig.json"strict": true 또는 최소 "strictNullChecks": true 가 있어야 이 모든 패턴이 의미 있음.

🧪 검증 상태

  • verification_status: conceptual
  • Kotlin / Swift / Rust 의 default null safety 모델, TypeScript strictNullChecks 가 표준.
  • 적용 사례 발견 시 applied_in 추가.

🔗 관련 문서