iBetter Books
수정

JavaScript는 자유로운 언어입니다

JavaScript는 세상에서 가장 자유로운 프로그래밍 언어 중 하나입니다. 변수에 어떤 값이든 넣을 수 있고, 함수에 아무 값이나 전달할 수 있으며, 객체에 언제든 새로운 속성을 추가할 수 있습니다.

let message = "안녕하세요";message = 42;           // 문자열이었던 변수에 숫자를 넣어도 됩니다message = true;         // 불리언도 됩니다message = { name: "Kim" }; // 객체도 됩니다

이 자유로움 덕분에 JavaScript는 배우기 쉽고, 빠르게 프로토타입을 만들 수 있습니다. 웹 브라우저에서 시작해 서버(Node.js), 모바일 앱(React Native), 데스크톱 앱(Electron)까지 확장한 JavaScript의 성공에는 이 자유로움이 큰 역할을 했습니다.

자유에는 대가가 따릅니다

그런데 이 자유로움이 때로는 큰 문제를 만듭니다. 다음 코드를 봐주세요.

function getFullName(user) {  return user.firstName + " " + user.lastName;}const result = getFullName("Kim");console.log(result); // "undefined undefined"

getFullName 함수는 user 객체를 받아서 이름을 합치는 함수입니다. 그런데 실수로 문자열 "Kim"을 전달했습니다. JavaScript는 아무런 에러 없이 이 코드를 실행합니다. "Kim".firstNameundefined이고, "Kim".lastNameundefined이니까 결과는 "undefined undefined"가 됩니다.

이런 버그는 찾기가 정말 어렵습니다. 코드를 작성할 때는 에러가 나지 않고, 실행할 때도 에러가 나지 않으며, 사용자가 이상한 결과를 보고 나서야 비로소 알게 됩니다.

실제로 일어나는 일들

JavaScript의 자유로움이 만드는 문제는 생각보다 흔합니다.

오타 하나가 만드는 버그

const config = {  serverUrl: "https://api.example.com",  timeout: 3000,};// 오타: serverUrl이 아니라 serverurlfetch(config.serverurl); // undefined → 에러 없이 실행됨

serverUrlserverurl로 잘못 썼지만, JavaScript는 이를 undefined로 처리하고 넘어갑니다. 나중에 네트워크 요청이 실패해서야 원인을 찾게 됩니다.

잘못된 타입의 연산

function calculateTotal(price, quantity) {  return price + quantity;}const total = calculateTotal(1000, 3);console.log(total); // 1003 — 숫자끼리 더하면 정상입니다const total2 = calculateTotal("1000", "3");console.log(total2); // "10003" — 문자열끼리 더하면 문자열 연결이 됩니다!

calculateTotal 함수는 가격과 수량을 더하는 함수입니다. 숫자를 전달하면 1003이 되지만, 실수로 문자열을 전달하면 + 연산자가 문자열 연결로 동작하여 "10003"이 됩니다. JavaScript는 이 차이를 아무런 경고 없이 넘어갑니다. 이런 암묵적 형변환은 예측하기 어려운 버그의 원인이 됩니다.

존재하지 않는 메서드 호출

const numbers = [1, 2, 3];numbers.toUpperCase(); // TypeError: numbers.toUpperCase is not a function

이 에러는 코드를 실행해야만 알 수 있습니다. 개발자가 배열에 문자열 메서드를 호출하는 실수를 했지만, 에디터는 아무런 경고도 주지 않습니다.

프로젝트가 커지면 문제도 커집니다

혼자서 작은 프로젝트를 만들 때는 이런 문제가 크게 느껴지지 않을 수 있습니다. 변수가 어떤 타입인지 머릿속에 다 기억할 수 있으니까요.

하지만 프로젝트가 커지면 이야기가 달라집니다.

  • 파일이 수십, 수백 개로 늘어납니다
  • 다른 사람이 작성한 코드를 수정해야 합니다
  • 6개월 전에 내가 작성한 코드를 다시 봐야 합니다
  • API에서 받아오는 데이터의 구조가 바뀝니다

이런 상황에서 "이 변수에 무슨 값이 들어있지?", "이 함수에 뭘 전달해야 하지?"라는 질문에 답하기가 점점 어려워집니다.

TypeScript라는 해결책

이 모든 문제의 근본 원인은 하나입니다. JavaScript가 변수와 함수의 "타입"을 강제하지 않는다는 것입니다.

TypeScript는 바로 이 문제를 해결하기 위해 만들어졌습니다. TypeScript는 JavaScript에 타입 시스템을 추가한 언어입니다. 코드를 작성하는 시점에 "이 변수는 문자열입니다", "이 함수는 객체를 받습니다"라고 명시하면, TypeScript가 코드를 실행하기 전에 잘못된 부분을 찾아줍니다.

앞에서 본 getFullName 함수를 TypeScript로 작성하면 이렇게 됩니다.

interface User {  firstName: string;  lastName: string;}function getFullName(user: User): string {  return user.firstName + " " + user.lastName;}getFullName("Kim"); // 에러! 'string' 타입은 'User' 타입에 할당할 수 없습니다.

코드를 작성하는 순간, 에디터에 빨간 밑줄이 그어집니다. 실행하기 전에, 사용자가 보기 전에, 버그를 잡을 수 있습니다.

이 책에서 함께 배울 것

이 책에서는 TypeScript의 타입 시스템을 왜 사용하는지, 어떻게 동작하는지 차근차근 알아봅니다. 어려운 개념도 비유와 예제를 통해 자연스럽게 이해할 수 있도록 구성했습니다.

JavaScript의 자유로움을 포기하는 것이 아닙니다. TypeScript는 JavaScript의 자유로움 위에 안전장치를 더하는 것입니다. 마치 자동차의 에어백처럼, 평소에는 눈에 보이지 않지만 위험한 순간에 여러분을 지켜줍니다.

다음 챕터에서는 JavaScript와 TypeScript를 나란히 놓고 구체적으로 어떤 차이가 있는지 살펴보겠습니다.