iBetter Books
수정

Ch 02. JavaScript vs TypeScript

같은 코드를 두 언어로 나란히 작성해봅니다. 차이를 읽으면서 TypeScript가 무엇을 추가하는지 파악합니다.

변수와 타입 추론

JavaScript는 런타임에 타입을 결정합니다. TypeScript는 컴파일 시점에 타입을 확인합니다.

// JavaScriptlet count = 0;count = "hello";     // 아무 오류 없음count.toFixed(2);    // 런타임 오류: count.toFixed is not a function
// TypeScriptlet count = 0;       // 타입 추론: numbercount = "hello";     // 오류: Type 'string' is not assignable to type 'number'count.toFixed(2);    // 안전하게 사용 가능

TypeScript는 초깃값을 보고 타입을 추론합니다. count = 0이라 쓰면 number로 확정되어, 이후 다른 타입의 값을 넣으려 하면 컴파일 오류가 납니다.

함수 시그니처

JavaScript 함수는 어떤 인자든 받을 수 있습니다.

// JavaScriptfunction formatPrice(price, currency) {  return `${currency}${price.toFixed(2)}`;}formatPrice("free", "USD");   // 런타임 오류: price.toFixed is not a functionformatPrice(9.99);            // NaN — currency가 undefined

TypeScript에서는 함수의 계약을 명확하게 정의합니다.

// TypeScriptfunction formatPrice(price: number, currency: string): string {  return `${currency}${price.toFixed(2)}`;}formatPrice("free", "USD");   // 오류: Argument of type 'string' is not assignable to parameter of type 'number'formatPrice(9.99);            // 오류: Expected 2 arguments, but got 1formatPrice(9.99, "USD");     // 정상: "$9.99"

객체와 인터페이스

JavaScript에서 객체는 형태가 자유롭습니다.

// JavaScriptfunction getUserFullName(user) {  return `${user.firstName} ${user.lastName}`;}getUserFullName({ firstName: "Alice" });        // "Alice undefined"getUserFullName({ name: "Alice Smith" });        // "undefined undefined"getUserFullName(null);                           // 런타임 오류

TypeScript에서는 객체 형태를 인터페이스로 정의합니다.

// TypeScriptinterface User {  firstName: string;  lastName: string;  email?: string;   // ? 는 선택적 필드}function getUserFullName(user: User): string {  return `${user.firstName} ${user.lastName}`;}getUserFullName({ firstName: "Alice" });// 오류: Property 'lastName' is missing in type '{ firstName: string; }' but required in type 'User'getUserFullName({ name: "Alice Smith" });// 오류: Object literal may only specify known properties, and 'name' does not exist in type 'User'getUserFullName(null);// 오류: Argument of type 'null' is not assignable to parameter of type 'User'getUserFullName({ firstName: "Alice", lastName: "Smith" });   // 정상

실제 버그 사례 비교

실무에서 자주 등장하는 패턴입니다. API 응답을 처리하는 코드입니다.

// JavaScript — 버그가 숨어있는 코드async function loadUserProfile(userId) {  const response = await fetch(`/api/users/${userId}`);  const data = await response.json();  // data.user 가 없는 경우? data.profile 인 경우?  // 잘못된 키로 접근해도 컴파일러는 조용  return {    name: data.user.name,    avatar: data.user.avatarUrl,   // avatarUrl? avatar_url?    joinedAt: data.user.createdAt,  };}

TypeScript에서는 API 응답 타입을 정의하고, 형태가 맞지 않으면 오류를 냅니다.

// TypeScript — 타입 안전한 코드interface ApiUser {  id: number;  name: string;  avatar_url: string;  created_at: string;}interface ApiResponse {  user: ApiUser;}async function loadUserProfile(userId: number): Promise<{  name: string;  avatar: string;  joinedAt: string;}> {  const response = await fetch(`/api/users/${userId}`);  const data: ApiResponse = await response.json();  return {    name: data.user.name,    avatar: data.user.avatar_url,    joinedAt: data.user.created_at,  };}// 아래 호출은 컴파일 시 바로 오류 발생loadUserProfile("not-a-number");   // 오류: Argument of type 'string' is not assignable to parameter of type 'number'

null과 undefined 처리

JavaScript에서 null은 유명한 버그의 원인입니다.

// JavaScriptfunction getFirstItem(arr) {  return arr[0].name;   // arr가 빈 배열이면? arr[0]이 없으면?}getFirstItem([]);   // 런타임 오류: Cannot read properties of undefined

TypeScript의 strict 모드는 null 가능성을 컴파일 시점에 강제합니다.

// TypeScript — strict 모드interface Item {  name: string;}function getFirstItem(arr: Item[]): string | undefined {  return arr[0]?.name;   // 옵셔널 체이닝으로 안전하게 접근}const result = getFirstItem([]);// result 를 바로 사용하려 하면 오류console.log(result.toUpperCase());// 오류: Object is possibly 'undefined'// null 체크를 하면 통과if (result !== undefined) {  console.log(result.toUpperCase());   // 정상}

TypeScript는 JavaScript의 상위 집합

중요한 사실 하나입니다. 모든 유효한 JavaScript 코드는 TypeScript 코드이기도 합니다.

// 이 코드는 TypeScript 파일(.ts)에서도 완벽히 유효const names = ["Alice", "Bob", "Carol"];names.forEach(name => console.log(name));

TypeScript는 JavaScript에 타입 문법을 얹은 것입니다. 컴파일하면 타입 정보가 제거된 순수 JavaScript가 나옵니다.

// 입력: TypeScriptfunction greet(name: string): string {  return `Hello, ${name}!`;}
// 출력: JavaScript (컴파일 후)function greet(name) {  return `Hello, ${name}!`;}

브라우저와 Node.js는 TypeScript를 직접 실행하지 않습니다. tsc 컴파일러가 JavaScript로 변환해줍니다. 다음 PART에서 직접 설치하고 확인합니다.

정리

항목 JavaScript TypeScript
타입 확인 시점 런타임 컴파일 타임
오류 발견 시점 실행 후 코드 작성 중
객체 구조 강제 없음 인터페이스로 정의
null 안전성 개발자 책임 strict 모드로 강제
브라우저 실행 직접 가능 컴파일 후 실행

TypeScript는 JavaScript를 대체하는 게 아닙니다. 더 안전하게 JavaScript를 작성할 수 있도록 돕는 도구입니다.