본문 바로가기
C.W.K.
Stream
Lesson 02 of 06 · published

타입 위치의 `typeof`: 값에서 모양 가져오기

~8 min · type-manipulation, typeof, type-from-value

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"이미 잘 만든 값이 있다면, 그 모양을 타입으로 다시 받아 적지 마."

같은 철자, 다른 시간대

값 표현식의 typeof x는 실행 중에 'string' 같은 문자열을 돌려줘. 반면 타입 위치의 typeof x는 컴파일러가 알고 있는 x의 정적 타입을 가져와. const user = { id: 1, name: 'Pippa' } 다음에 type User = typeof user라고 쓰면 User는 그 객체 모양을 그대로 따른다.

두 연산자는 철자가 같아도 목적이 달라. 하나는 런타임 분기용이고, 다른 하나는 타입 선언을 값과 동기화하기 위한 도구야. 코드를 읽을 때 typeof가 값 자리에 있는지, type이나 제네릭 인자 같은 타입 자리에 있는지 먼저 보면 헷갈리지 않아.

값을 기준 원본으로 삼기

경로표나 설정처럼 실제 실행에 쓰이는 상수가 먼저라면 typeof가 특히 좋아. const ROUTES = { home: '/', chat: '/chat' } as const에서 type Routes = typeof ROUTES를 만들면 값과 타입이 한 선언에서 출발해. 키만 필요하면 keyof typeof ROUTES, 경로 값만 필요하면 (typeof ROUTES)[keyof typeof ROUTES]까지 이어갈 수 있지.

여기서 as const가 없으면 문자열 값이 일반 string으로 넓어질 수 있어. typeof는 선언된 값보다 더 정밀한 정보를 발명하지 않아. 리터럴 자체가 의미 있는 API라면 먼저 값의 추론 폭을 적절히 고정해야 해.

함수와 라이브러리에서 재사용하기

함수도 값이므로 typeof fetchUser로 함수 타입을 얻을 수 있어. 여기에 ReturnType<typeof fetchUser>Parameters<typeof fetchUser>를 붙이면 이미 구현된 함수에서 결과와 인자 타입을 파생한다. 이름 없는 콜백의 모양을 억지로 복사하기보다 원본 함수와 연결하는 편이 변경에도 강해.

다만 공개 계약이 구현 세부에 끌려가면 곤란할 수 있어. 도메인의 안정된 경계를 표현하는 타입은 명시적으로 이름 붙이는 편이 낫고, 구현과 함께 움직여야 하는 보조 타입은 typeof로 파생하는 편이 좋아. 파생 가능하다는 이유만으로 모든 타입을 파생할 필요는 없어.

타입 위치의 typeof는 값과 타입의 중복 선언을 없애는 다리야. 무엇이 원본이어야 하는지 먼저 정하고, 값이 원본인 곳에서만 이 다리를 건너.

Code

typeof 통한 값 → 타입·typescript
// 상수에서 타입.
const defaultUser = {
  id: 0,
  name: 'anon',
  permissions: [] as string[],
};

type User = typeof defaultUser;
// { id: number; name: string; permissions: string[] }

// 함수에서 signature.
function fetchPost(id: number): Promise<{ title: string; body: string }> {
  return Promise.resolve({ title: '', body: '' });
}

type FetchPostFn = typeof fetchPost;
// (id: number) => Promise<{ title: string; body: string }>

type FetchPostReturn = ReturnType<typeof fetchPost>;
// Promise<{ title: string; body: string }>

// External library.
import { someConfig } from 'their-library';
type TheirConfig = typeof someConfig;     // 타입 export 안 할 때 회복

External links

Exercise

복잡한 설정 객체에서 typeof로 타입을 파생하고 손으로 적은 모양과 비교해. as const를 추가했을 때 값과 읽기 전용 정보가 어떻게 좁아지는지도 봐.
Hint
as const가 없으면 문자열 리터럴이 일반 문자열로 넓어질 수 있어. 값을 고정하면 typeof가 구체 리터럴까지 보존해.

Progress

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

댓글 0

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

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