C.W.K.
Stream
Lesson 04 of 05 · published

Type Predicate: `is` 함수

~11 min · narrowing, type-predicates, type-guards, user-defined

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"typeof, instanceof, `in` 으로 안 될 때 자기 narrowing 함수 써."

Type predicate 의 형태

Type predicate 가 arg is T return type annotation 가진 함수. Signature 가 function isUser(x: unknown): x is User 처럼 보임. 함수 body 가 평소대로 boolean 반환. 마법은 return type 에: 함수가 true 반환하면, caller 가 `arg` 가 `T` 타입인 거 배워.

Caller 관점에서 predicate 호출은 typeof 나 instanceof 체크 같아 — 값이 true 분기 안에서 narrow.

안에 뭐 들어가

Predicate 의 body 가 runtime 에 돌아. 타입 검증에 필요한 어떤 체크든 함: property 존재, 값 타입, 구조 매칭, 심지어 다른 predicate 호출. Compiler 가 predicate 신뢰 — true 반환하면 narrowing 발생. (즉 버그 있는 predicate 가 compiler 한테 거짓말; body 신중히 구조화.)

외부 source (JSON, 사용자 입력, 3rd-party API) 에서 온 unknown 입력엔, predicate 가 너의 validation. Zod, Valibot, io-ts 같은 tool 이 이 패턴을 타입-안전 predicate 만드는 parser-generator 로 감싸.

자기 거 쓸 때

  • 타입 안 붙은 데이터 validating (parse 된 JSON, dynamic fetch).
  • 깨끗한 discriminator 없는 union 의 object 모양 체크.
  • 단일 typeof/instanceof 에 너무 복잡한 체크 감싸기.
Compiler 가 너의 predicate 신뢰. Predicate 가 실제로 `T` match 안 하는 object 에 true 반환하면, type system 이 이제 거짓말. JSON parser 와 같은 주의로 predicate 써 — 안 안전 입력과 안전 코드 사이의 경계.

Code

커스텀 isUser predicate·typescript
interface User { name: string; email: string }

// Type predicate — return type 'x is User' 주목.
function isUser(x: unknown): x is User {
  return (
    typeof x === 'object' && x !== null &&
    'name' in x && typeof (x as any).name === 'string' &&
    'email' in x && typeof (x as any).email === 'string'
  );
}

// 다른 narrowing 체크처럼 써.
function handle(input: unknown) {
  if (isUser(input)) {
    // 여기서 input 이 User 로 narrow.
    return `Hello, ${input.name}`;
  }
  return 'Invalid input';
}

// Predicate 없으면 property 체크 inline 으로 narrow — 길고,
// 재사용 불가능, 끝에 User-typed 접근 잃어.
조합 가능한 predicate 와 Array.isArray·typescript
// 배열-specific predicate — Array.isArray 가 built-in type predicate.
function processItems(x: unknown) {
  if (Array.isArray(x)) {
    // x 가 any[] 로 narrow (built-in predicate)
    return x.length;
  }
  return 0;
}

// 중첩 구조에 predicate compose 가능.
function isStringArray(x: unknown): x is string[] {
  return Array.isArray(x) && x.every((v) => typeof v === 'string');
}

function collect(input: unknown) {
  if (isStringArray(input)) {
    // input: string[]
    return input.join(', ');
  }
  return '';
}

External links

Exercise

Predicate isApiResponse(x: unknown): x is { status: number; data: unknown } 써. statusdata 의 property-존재와 타입 체크 써. 그다음 fetch().then(r => r.json()) 의 결과 소비하고 predicate 써서 안전하게 data 접근하는 함수 써.
Hint
Body 가 x 가 object 인지, null 아닌지, status 가 number 인지, data 가지는지 (predicate 가 outer 모양만 narrow 하니까 data 는 unknown 으로 둘 수) 검증 필요. 한 번 narrow 되면 더 많은 predicate 써서 data 안으로 파고들 수.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.