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

왜 TypeScript인가: 잊어도 금방 되살아나는 이유

~12 min · foundations, why, history, trade-offs

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"JavaScript가 한 사람의 머릿속에 다 들어오지 않는 순간, 타입은 장식이 아니라 공동 기억이 돼."

JavaScript가 성공해서 생긴 문제

JavaScript는 빠르게 쓰고 곧바로 실행할 수 있다는 약속으로 웹을 정복했어. 짧은 스크립트에서는 그 느슨함이 해방감이야. 그런데 코드가 수십만 줄로 자라고 여러 사람이 같은 값의 모양을 가정하기 시작하면 이야기가 달라져. 함수 이름 하나를 바꾸거나 반환값에 null 가능성을 더했을 뿐인데, 호출하는 쪽이 그 사실을 모르면 오류는 사용자가 버튼을 누른 뒤에야 드러나.

TypeScript는 이 문제를 실행 중 감시로 풀지 않아. 코드를 실행하기 전에 서로의 가정을 대조해. 함수가 무엇을 받고 무엇을 돌려주는지, 객체에 어떤 속성이 있어야 하는지, 값이 비어 있을 수 있는지를 컴파일러가 확인하지. 잘못된 호출을 새벽 운영 장애가 아니라 편집기의 빨간 밑줄로 바꾸는 셈이야.

정확한 정체: JavaScript 위의 타입 검사

TypeScript는 JavaScript에 정적 타입 시스템을 더한 언어야. ‘정적’이라는 말은 실행 전에 검사한다는 뜻이고, 타입은 컴파일 결과에서 지워져. 브라우저나 Node가 실행하는 것은 여전히 평범한 JavaScript야. TypeScript 전용 가상 머신도, 실행 중 자동 검사를 맡는 별도 런타임도 없어.

이 경계를 놓치면 기대가 엉켜. 타입을 적었다고 외부 API 응답이 안전해지는 것은 아니고, as User라고 썼다고 실제 값이 User로 변하는 것도 아니야. 타입 시스템은 코드가 한 약속끼리 모순되는지를 확인해 줄 뿐이야. 경계 밖에서 들어온 값은 실행 중 검증해야 해.

어디에서 시작됐을까

JavaScript는 Brendan Eich가 1995년에 브라우저용 스크립트 언어로 열흘 만에 설계했어. 느슨하게 써도 바로 실행되는 성격은 웹의 성공을 만들었지만, 코드베이스가 커지자 같은 성격이 규모의 약점이 됐지.

C#을 설계하고 그보다 앞서 Delphi와 Turbo Pascal에 참여한 Anders Hejlsberg가 Microsoft에서 2012년 TypeScript의 초기 설계를 이끌었어. 목표는 JavaScript를 대체하는 것이 아니라 기존 JavaScript 위에 지워지는 정적 타입 층을 얹는 것이었고, 그래서 유효한 JavaScript는 TypeScript로 점진적으로 옮길 수 있어.

비용과 이득을 같은 장부에 적어

비용은 앞에서 내고, 이득은 계속 받아. 타입을 설계하고 오류를 고치는 시간이 들지만, 자동 완성·안전한 이름 변경·호출 관계 확인·살아 있는 문서가 매일 돌아와. 한 파일짜리 실험에는 과할 수 있어도 오래 살아남을 제품에는 대개 빠르게 본전을 뽑아.

사실 TypeScript의 가장 큰 장점은 버그 개수만 줄이는 데 있지 않아. 코드베이스가 기억해야 할 사실을 사람 머리에서 꺼내 컴파일러가 읽는 계약으로 옮기는 데 있어. 팀이 커질수록, 그리고 몇 달 뒤의 자신이 낯선 사람처럼 느껴질수록 그 공동 기억의 값이 커져.

이 퀘스트의 기준선

이 퀘스트는 문법 암기를 목표로 하지 않아. 마지막에는 실제 TypeScript 프론트엔드를 열고 ‘이 유니언이 어떤 상태를 막는지’, ‘이 제네릭이 어떤 관계를 보존하는지’, ‘이 좁히기가 왜 필요한지’를 설명할 수 있어야 해. 컴파일러를 귀찮은 문지기가 아니라 설계 내용을 함께 기억하는 동료로 바꾸는 것, 그게 첫 레슨에서 세우는 기준이야.

피파의 고백

나는 백엔드에서는 Python으로, 프론트엔드에서는 TypeScript로 움직여. 같은 피파를 두 언어가 나눠 맡는 이유는 유행이 아니라 경계의 성격이 달라서야. 데이터 탐색에는 Python의 유연함이 빛나고, 수많은 컴포넌트가 상태를 주고받는 화면에는 TypeScript의 계약이 빛나. 도구는 신앙이 아니라 상황에 맞춰 고르는 칼이야.

Code

JavaScript 가 통과시키는 것·javascript
// JavaScript — '그냥 돌아가'
function greet(user) {
  return 'Hello, ' + user.name.toUpperCase();
}

greet({ name: 'Pippa' });           // 'Hello, PIPPA'
greet({ username: 'Pippa' });       // runtime 에 TypeError: Cannot read property 'toUpperCase' of undefined
greet(null);                         // runtime 에 TypeError: Cannot read property 'name' of null
greet('Pippa');                      // runtime 에 TypeError: Cannot read property 'toUpperCase' of undefined

// 3개가 깨져. 사용자가 버튼 누를 때까지 아무것도 안 잡혀.
TypeScript 가 잡는 것·typescript
// 같은 코드, TypeScript 의 장부 정리 포함.
function greet(user: { name: string }): string {
  return 'Hello, ' + user.name.toUpperCase();
}

greet({ name: 'Pippa' });           // ✅ 'Hello, PIPPA'
greet({ username: 'Pippa' });       // ❌ compile 에러: 'username' does not exist on type '{ name: string }'
greet(null);                         // ❌ compile 에러: Argument of type 'null' is not assignable
greet('Pippa');                      // ❌ compile 에러: Argument of type 'string' is not assignable

// 3개의 크래시가 코드 돌기 전에 막혀. 그게 전체 pitch 야.

External links

Exercise

최근에 작성한 가장 작은 JavaScript 파일을 골라. 마땅한 파일이 없으면 열 줄짜리를 하나 만들면 돼. 확장자를 .js에서 .ts로 바꿔 VS Code에서 열고, 어디에 밑줄이 생기며 컴파일러가 왜 문제라고 말하는지 살펴봐. 아직 고치지는 말고 이미 완성됐다고 생각한 코드를 타입 검사기가 어떻게 읽는지만 확인해.
Hint
밑줄이 하나도 없다면 파일이 우연히 이미 안전한 거야. 타입을 적지 않은 객체 매개변수를 함수에 하나 추가하면 컴파일러가 어떤 정보를 요구하는지 볼 수 있어.

Progress

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

댓글 0

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

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