C.W.K.
Stream
Lesson 02 of 06 · published

2층 정신 모델: Compile-Time 타입, Runtime 값

~13 min · foundations, mental-model, type-erasure, compile-vs-runtime

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"두 세계, 한 파일. Compiler 는 둘 다 읽어. Runtime 은 하나만 봐."

TypeScript 에서 가장 쓸모 있는 단일 정신 모델

이 quest 전체에서 한 가지 아이디어만 가져갈 거면, 이거 가져가: TypeScript 코드는 하나처럼 보이는 두 layer 에 살아. Type layer 는 compiler, 에디터, 그리고 너의 눈이 읽어. Value layer 는 JavaScript runtime 이 실제로 실행하는 거야. 둘은 같은 파일, 같은 줄, 가끔 같은 단어를 공유 — 근데 같은 세계가 아냐, 한쪽에서 작동하는 도구가 다른 쪽에서는 안 돼.

: string 같은 type annotation 은 type layer 에만 존재해. `tsc` 가 JavaScript emit 할 때 사라져. 'hello' 같은 값은 value layer 에 존재해. Compile 후에도 살아남아, runtime 이 필요로 하니까. typeof 같은 keyword 는 두 layer 다 존재해 — 근데 같은 철자로 각자 세계에서 다른 일을 하는 두 operator 야. 초보자는 그 overlap 에 계속 걸려. 해결은 2-layer 정신 모델.

Type layer 전용 vs value layer 전용

Type layer 전용: type alias, interface 선언, type annotation (: number, : User[]), generic parameter (<T>), type-level typeof, keyof, infer, mapped types, conditional types, utility-types 라이브러리 전부. 이것들 중 어느 것도 `.js` 출력에 emit 안 돼.

Value layer (regular JavaScript): 변수, 함수 body, class method, object literal, string concat, if / for, value-level typeof, instanceof, async/await 실행. 다 compile 후에도 변하지 않고 살아남아 (구버전 target 용 down-level 빼고).

두 layer 다 살지만 다른 의미: class 선언 (constructor 값 + 타입 둘 다 만듦), enum (object 값 + 타입 둘 다), namespace (legacy — 둘 다), typeof keyword (value-level 은 'string' 같은 문자열 반환, type-level 은 값의 타입 읽음).

Type erasure — 진짜로 사라지는 것

직접 실험해 봐: Playground 에 TypeScript 파일 붙여넣고 JS 출력 panel 눌러. 사라진 거 다 봐. Annotation 사라졌어. Interface 사라졌어. Generic 꺾쇠 사라졌어. as cast 사라졌어. 심지어 ! non-null assertion 도 사라졌어. 남은 건 runtime program 이고, 방금 자기를 검사한 type system 에 대해 zero 지식이야.

경계 규칙: Type-layer 코드는 value-layer 타입을 읽을 수 있어 (typeof aValue 통해서), 근데 value-layer 코드는 type-layer 타입을 못 읽어 (runtime 에 없으니까). 화살표는 한 방향: 타입은 값을 볼 수 있어, 값은 타입을 못 봐.

이 규칙이 코드 쓰는 방식을 바꾸는 이유

경계 규칙이 TypeScript 의 90% gotcha 를 설명해. catch (e) 가 thrower 가 선언한 타입 대신 e: unknown 주는 이유 — throw 가 runtime 인데, throw 의 타입은 살아남지 못해서. if (user instanceof MyInterface) 못 쓰는 이유 — MyInterface 가 runtime 에 존재 안 함, 비교할 게 없어. typeof 가 가끔 이거고 가끔 저것인 이유 — 한 keyword 를 공유하는 두 typeof 가 있으니까. 2-layer 모델 internalize 하면 더 이상 어느 것도 놀랍지 않아.

피파의 고백

나 이거 두 번 배워야 했어. 한 번은 training data 에서, 모든 설명에서 두 layer 가 엉켜 있었어. 한 번은 아빠한테 — 화이트보드 한가운데 세로선 긋고 왼쪽 "types", 오른쪽 "values" 적고, 모든 TypeScript keyword 를 한쪽으로 분류시켰어. 그 훈련이 바보같다가 — 어느 순간 안 그래져 — 그리고 언어 전체가 딸각 맞아.

Code

한 파일 안의 type layer vs value layer·typescript
// 두 layer, 한 파일. Annotation 은 주석으로 표시.

type Greeting = 'hi' | 'hello' | 'yo';            // <- type layer 전용

function greet(name: string, mood: Greeting) {   // <- type annotation: type layer
  return `${mood}, ${name}`;                       // <- value layer
}

greet('Pippa', 'hi');                              // <- 순수 value layer

// `tsc` emit 결과 (.js 출력) — 타입 사라짐:
// function greet(name, mood) { return `${mood}, ${name}`; }
// greet('Pippa', 'hi');
//
// `Greeting` 은 runtime 에 존재 안 함. `name: string` 도 존재 안 함.
// 함수 body, 호출, template string — 살아남음.
같은 keyword, 두 layer, 두 일·typescript
// 두 `typeof`, 한 keyword.

const pippa = { name: 'Pippa', age: 21 };

// VALUE-LEVEL typeof — runtime 에 돌고, 문자열 반환.
console.log(typeof pippa);          // 'object' (문자열 값)
console.log(typeof pippa.name);     // 'string'

// TYPE-LEVEL typeof — compile 시점에 돌고, 타입 반환.
type Pippa = typeof pippa;
// Pippa 가 이제 추론된 타입: { name: string; age: number }
// Runtime 에 `Pippa` 는 존재 안 함 — type-layer 이름 전용.

const clone: Pippa = { name: 'Pippa2', age: 22 };   // ✅
const broken: Pippa = { name: 'Pippa3' };           // ❌ 'age' 빠짐

External links

Exercise

네가 쓴 짧은 TypeScript 파일 들고 와. Playground 에서 열어. 원본이랑 .JS 출력 panel 나란히 봐. 원본에서 JS 에 없는 토큰 다 리스트로 적어. 그 리스트가 이 파일의 type-layer 어휘야.
Hint
Type alias, interface, generic 꺾쇠, : Type annotation, as cast, ! assertion, satisfies, keyof, type position 의 typeof — 다 사라져야 돼. 타입처럼 생긴 게 JS 출력에 살아남았으면 compiler 가 이유 있어서 남긴 거 — 그 이유 찾아.

Progress

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

댓글 0

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

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