JS 퀴즈북 × 이펙티브 타입스크립트 읽기 지도.
JavaScript Quizbook 13일과 Effective TypeScript 2판 14일을 값, 참조, 스코프, 비동기, 타입 설계, 런타임 검증, 마이그레이션 주제로 다시 묶어 읽는 안내서입니다.
대상 글: JavaScript Quizbook 리마인드 Day 1–13, Effective TypeScript 2판 Day 1–14
이 글의 목적: 두 시리즈를 순서대로 다 읽은 뒤, 프론트엔드 코드 리뷰 질문별로 다시 찾아 들어갈 수 있게 만드는 지도
두 시리즈는 처음부터 역할이 조금 달랐습니다. JavaScript Quizbook 리마인드는 런타임에서 실제로 값이 어떻게 움직이는지를 붙잡는 글이고, Effective TypeScript 2판 시리즈는 그 움직임을 타입과 API 경계로 어떻게 좁히고 표현할지를 보는 글입니다.
그래서 복습할 때는 “JS 1일부터 TS 14일까지 다시 정주행”보다, 지금 리뷰 중인 코드가 어떤 질문을 던지는지부터 잡는 편이 낫습니다.
먼저 읽을 글은 JavaScript Quizbook Day 1–3입니다.
[Day 1: 숫자 모델과 NaN](/blog/study/javascript-quizbook/day1) [Day 2: 동등성 알고리즘](/blog/study/javascript-quizbook/day2) [Day 3: 강제 변환과 ToPrimitive](/blog/study/javascript-quizbook/day3)
이 구간은 “왜 이 값이 같다고 나오지?”, “왜 빈 문자열이 빠졌지?”, “왜 +가 문자열 연결로 바뀌지?” 같은 버그를 다룹니다. 런타임 규칙을 모르면 TypeScript 쪽에서 string | number를 얼마나 예쁘게 표현해도 리뷰가 흔들립니다.
같이 읽을 TypeScript 글은 Day 1–2입니다.
[Effective TS Day 1: TS/JS 관계와 any 경계](/blog/study/effective-typescript/day1) [Effective TS Day 2: 타입은 값의 집합이다](/blog/study/effective-typescript/day2)
여기서 연결되는 질문은 하나입니다.
타입은 가능한 값의 집합을 줄여주지만, 런타임 비교와 변환 규칙을 대신 실행해주지는 않는다.
예를 들어 id: string | number를 허용하는 순간, 비교 정책도 같이 정해야 합니다. ==로 느슨하게 맞출지, API 경계에서 문자열로 정규화할지, 아예 서로 다른 타입으로 나눌지 결정해야 합니다. TypeScript는 그 결정을 표현할 수 있지만, 결정 자체를 대신 해주지는 않습니다.
객체 복사, Map/Set, WeakMap, 얕은 복사 문제는 JavaScript Quizbook Day 4–5로 돌아가면 됩니다.
[Day 4: 프로퍼티 descriptor와 객체 제한](/blog/study/javascript-quizbook/day4) [Day 5: 참조, 복사, Map/Set](/blog/study/javascript-quizbook/day5)
이 구간의 핵심은 “새 값처럼 보이는 것이 정말 새 값인가?”입니다. `는 최상위 객체만 새로 만들 수 있고, const는 객체 내부 불변을 보장하지 않으며, Map`은 key를 강하게 붙잡을 수 있습니다.
TypeScript 쪽에서는 Day 6과 연결됩니다.
[Effective TS Day 6: 유효한 상태만 표현하는 타입 설계](/blog/study/effective-typescript/day6)
상태 타입을 잘 만들었다고 해도, 앱 내부에서 같은 객체 참조를 여러 캐시와 UI 상태가 공유하면 이상한 변경이 퍼질 수 있습니다. 반대로 참조 모델을 잘 이해해도, loading: boolean; data?: T; error?: string처럼 불가능한 상태 조합을 허용하면 렌더링 branch가 복잡해집니다.
리뷰 순서는 이렇게 잡으면 좋습니다.
| 질문 | 먼저 볼 글 | 이어서 볼 글 |
|---|---|---|
| 복사한 객체가 원본을 바꾸는가? | JS Day 5 | TS Day 6 |
| 캐시가 객체를 계속 붙잡는가? | JS Day 5 | TS Day 8 |
| 상태 조합이 이상한가? | TS Day 6 | JS Day 4–5 |
readonly/as const가 안전해 보이지만 런타임은 다른가? | TS Day 3, TS Day 6 | JS Day 4 |
오래된 값, stale closure, await 뒤 최신성 문제는 JavaScript Quizbook Day 6–8을 한 묶음으로 봐야 합니다.
[Day 6: 스코프 체인과 호이스팅](/blog/study/javascript-quizbook/day6) [Day 7: 클로저 버그와 오래된 값](/blog/study/javascript-quizbook/day7) [Day 8: 이벤트 루프와 Promise 타이밍](/blog/study/javascript-quizbook/day8)
이 세 글은 순서가 중요합니다. Day 6은 “함수가 어느 바인딩을 보나”를 잡고, Day 7은 “그 바인딩이 나중에 실행될 때 오래될 수 있나”를 묻고, Day 8은 “그 나중이 정확히 어느 큐 뒤인가”를 봅니다.
TypeScript에서는 Day 5, Day 13과 연결됩니다.
[Effective TS Day 5: narrowing과 async/type flow](/blog/study/effective-typescript/day5) [Effective TS Day 13: 런타임 타입, DOM, 테스트, 성능](/blog/study/effective-typescript/day13)
TypeScript가 if (!currentUser) return 뒤의 타입을 좁혀줘도, await 동안 전역 상태가 바뀌는지까지 보장하지는 않습니다. DOM 타입이 정확해도, 실제 브라우저 이벤트와 렌더 타이밍을 테스트하지 않으면 깨질 수 있습니다.
리뷰할 때는 이 질문을 그대로 쓰면 됩니다.
이 함수는 어디서 만들어졌고, 언제 실행되며, 그 사이 어떤 값이 바뀔 수 있나?
Effective TypeScript Day 3–7은 타입 설계의 기본 골격입니다.
[Day 3: excess property, 함수 타입, type/interface, readonly](/blog/study/effective-typescript/day3) [Day 4: index signature와 추론 기본](/blog/study/effective-typescript/day4) [Day 5: narrowing과 흐름](/blog/study/effective-typescript/day5) [Day 6: 유효한 상태와 API 경계](/blog/study/effective-typescript/day6) [Day 7: string, optional, special value, 이름](/blog/study/effective-typescript/day7)
이 구간은 “타입을 많이 적자”가 아니라 “검토해야 할 경우의 수를 줄이자”에 가깝습니다. string 하나로 모든 상태를 표현하면 간단해 보이지만, 실제로는 리뷰어가 가능한 문자열 전체를 머릿속에 들고 있어야 합니다. optional 필드가 많으면 객체 하나가 너무 많은 상태를 허용할 수 있습니다.
JavaScript 쪽에서는 Day 1–5가 배경입니다. 값의 실제 모양, 객체 참조, 프로퍼티 동작을 모른 채 타입만 좁히면 as const, readonly, Object.freeze 같은 말이 서로 섞입니다.
바로 Effective TypeScript Day 8로 가면 됩니다.
[Day 8: any, unknown, assertion, soundness traps](/blog/study/effective-typescript/day8)
이 글은 TypeScript 시리즈의 안전벨트에 가깝습니다. 외부 데이터, 라이브러리 틈, monkey patching, assertion을 다룰 때 “일단 통과시키는 타입”이 어디서 들어오는지 봐야 합니다.
같이 읽을 JavaScript 글은 상황에 따라 다릅니다.
외부 JSON 값의 숫자/문자열 혼합이면 JS Day 1–3 객체 shape와 프로퍼티 접근이면 JS Day 4–5 async 뒤 stale result면 JS Day 7–8
unknown은 귀찮은 타입이 아니라 “여기서 아직 모른다”는 표시입니다. 반대로 any는 그 표시를 지워버립니다. 리뷰에서는 any를 발견했을 때 바로 없애기보다, 어느 경계에서 검증하면 가장 작게 줄일 수 있는지부터 봐야 합니다.
Effective TypeScript Day 9–10을 읽으면 됩니다.
[Day 9: type coverage, generics, conditional/template literal types](/blog/study/effective-typescript/day9) [Day 10: type test, display, tail recursion, codegen, never exhaustiveness](/blog/study/effective-typescript/day10)
이 구간은 “타입 퍼즐”로 읽으면 금방 피곤해집니다. 프론트엔드 코드 리뷰 관점에서는 공개 API, route param, event name, design-system prop처럼 반복 규칙이 있는 문자열/객체를 얼마나 안전하게 표현할지에 가깝습니다.
JavaScript 쪽 연결은 Day 10–13입니다.
[JS Day 10: 함수와 아키텍처](/blog/study/javascript-quizbook/day10) [JS Day 11: prototype과 class](/blog/study/javascript-quizbook/day11) [JS Day 13: ESM과 모듈 경계](/blog/study/javascript-quizbook/day13)
타입이 복잡해지는 곳은 대개 런타임 구조도 복잡합니다. 함수 합성, 클래스 인스턴스, 모듈 export/import 경계가 흐린데 타입만 똑똑해지면 리뷰가 더 어려워질 수 있습니다.
DOM과 런타임 검증은 Effective TypeScript Day 13이 중심입니다.
[Effective TS Day 13: 런타임 타입, DOM, 환경 모델, 테스트](/blog/study/effective-typescript/day13)
이 글은 타입 시스템 바깥을 보는 훈련입니다. 브라우저 API는 타입 정의가 있어도 실제 DOM 상태, 렌더 타이밍, 이벤트 순서를 테스트해야 합니다. 그래서 JavaScript Quizbook Day 8, Day 12와 같이 읽는 편이 좋습니다.
[JS Day 8: 이벤트 루프와 Promise 타이밍](/blog/study/javascript-quizbook/day8) [JS Day 12: 브라우저 이벤트](/blog/study/javascript-quizbook/day12)
실제 리뷰에서는 이런 식으로 묻습니다.
타입은 HTMLElement라고 말하지만, 실제 selector가 항상 그 요소를 찾는가?
이벤트가 capture/bubble 어느 단계에서 처리되는가?
Promise/microtask 뒤 DOM 측정이 의도한 시점에 일어나는가?
unit test는 타입이 놓친 런타임 branch를 확인하는가?
마지막 묶음은 JavaScript Quizbook Day 13과 Effective TypeScript Day 14입니다.
[JS Day 13: ESM live binding과 모듈 경계](/blog/study/javascript-quizbook/day13) [Effective TS Day 14: JS 마이그레이션과 noImplicitAny](/blog/study/effective-typescript/day14)
모듈은 파일을 나누는 문법이 아니라 의존성과 실행 순서를 만드는 경계입니다. ESM live binding, circular dependency, dynamic import를 모르면 “분리했는데 왜 초기화 순서가 꼬이지?” 같은 문제가 남습니다.
TypeScript 마이그레이션은 여기서 현실적인 끝을 맺습니다. 모든 파일을 한 번에 .ts로 바꾸는 게 아니라, @ts-check, JSDoc, allowJs, 모듈별 변환, noImplicitAny 같은 단계로 위험을 줄입니다.
처음부터 다시 읽을 시간이 없다면 아래 네 경로 중 하나만 골라도 됩니다.
JS Day 1 JS Day 2 JS Day 3 Effective TS Day 2 Effective TS Day 8
JS Day 6 JS Day 7 JS Day 8 Effective TS Day 5 Effective TS Day 6 Effective TS Day 13
Effective TS Day 3 Effective TS Day 5 Effective TS Day 6 Effective TS Day 7 Effective TS Day 8 JS Day 5
Effective TS Day 1 Effective TS Day 14 JS Day 13 Effective TS Day 12 Effective TS Day 10
두 시리즈를 같이 읽는 이유는 “JS를 알고 TS를 쓰자”라는 구호 때문이 아닙니다. 코드 리뷰에서 실제로 필요한 질문이 서로 이어지기 때문입니다.
JavaScript는 값, 참조, 실행 순서, 모듈 경계를 보여줍니다. TypeScript는 그 경계 중 어디를 타입으로 표현하고, 어디를 런타임 검증과 테스트로 남겨야 하는지 보여줍니다. 프론트엔드 리뷰는 둘 중 하나만으로 끝나지 않습니다. 타입이 맞아도 런타임이 틀릴 수 있고, 런타임을 알아도 타입 설계가 상태 공간을 줄이지 못하면 유지보수가 어려워집니다.
복습할 때는 글 순서보다 리뷰 질문을 먼저 잡으면 됩니다. “이 버그는 값 비교인가, 참조 공유인가, 오래된 콜백인가, API 경계인가, 런타임 검증인가?” 그 질문이 정해지면 위 지도에서 다시 들어갈 글도 자연스럽게 정해집니다.
Post Q&A
JS 퀴즈북 × 이펙티브 타입스크립트 읽기 지도 전체를 기준으로 질문과 피드백을 받아요.답을 본 뒤에는 이 내용을 댓글로 달아서 서징에게도 물어볼 수 있어요. 작성자가 직접 볼 수 있어요!
Item 74–78 범위를 바탕으로 런타임 타입 재구성, DOM과 환경 모델, 단위 테스트 관계, 컴파일러 성능을 코드 리뷰 관점에서 정리합니다.