처음 TypeScript를 볼 때 잡아야 할 기준
TypeScript는 JavaScript를 버리고 새로 배우는 언어가 아니라, JavaScript 코드에 타입 검사 기준을 추가하는 방식입니다. 브라우저나 Node.js가 TypeScript를 그대로 실행하는 것이 아니라, TypeScript가 먼저 코드를 검사하고 최종적으로 JavaScript 코드로 변환됩니다.
JavaScript를 어느 정도 공부한 뒤 React나 Next.js 예제를 보면 갑자기 낯선 문법이 섞여 나옵니다. 변수 뒤에 : string이 붙고, 함수 인자 옆에 : number가 붙고, 어떤 코드는 interface나 type으로 객체 형태를 먼저 정리합니다. JavaScript 파일에서는 보지 못했던 표시가 많다 보니, 처음에는 기존 JavaScript와 완전히 다른 언어처럼 느껴질 수 있습니다.
하지만 TypeScript를 처음 배울 때 가장 먼저 정리해야 할 부분은 문법 목록이 아닙니다. TypeScript가 JavaScript와 어떤 관계인지, 그리고 타입 검사가 실제 실행과 어떻게 분리되는지를 먼저 이해해야 합니다. 이 기준이 잡히면 이후에 나오는 타입 추론, 타입 명시, 타입 오류, narrowing 같은 개념이 서로 따로 노는 문법이 아니라 하나의 흐름으로 보입니다.
TypeScript를 처음 볼 때 가장 먼저 풀어야 할 오해
![[기초 01] TypeScript란 무엇인가: JavaScript와 무엇이 다른가 1 TypeScript와 JavaScript의 관계를 타입 검사 레이어로 설명하는 UI 카드 이미지](https://blogflow.kr/wp-content/uploads/2026/06/02_body_image_1_compressed-8.jpg)
TypeScript를 처음 접하면 “JavaScript 대신 TypeScript를 배워야 하나?”라는 생각이 들기 쉽습니다. 이름도 다르고, 파일 확장자도 .js가 아니라 .ts를 쓰기 때문입니다. 그러나 TypeScript는 JavaScript를 대체하는 별도의 실행 환경으로 보는 것보다, JavaScript 위에 타입 검사 과정을 추가한 개발 도구로 이해하는 쪽이 더 정확합니다.
JavaScript 코드는 TypeScript 코드 안에서도 대부분 그대로 사용할 수 있습니다. 여기에 변수, 함수, 객체가 어떤 형태의 값을 다루는지 설명하는 타입 문법을 추가할 수 있습니다. 즉, TypeScript의 출발점은 JavaScript를 버리는 것이 아니라 JavaScript 코드의 의도를 더 명확하게 적는 것입니다. 화면 구현을 하던 기존 JavaScript 코드에 “이 값은 어떤 모양이어야 하는가”라는 기준표를 붙이는 쪽에 가깝습니다.
예를 들어 JavaScript에서는 다음과 같은 함수가 있을 때, 함수가 숫자를 받아야 하는지 문자열을 받아야 하는지 코드만 보고 애매할 수 있습니다.
function getDiscountPrice(price, discount) {
return price - discount;
}
getDiscountPrice(30000, 5000);
getDiscountPrice("30000", "5000");
첫 번째 호출은 숫자 계산 의도와 잘 맞습니다. 두 번째 호출은 문자열을 넘기고 있지만 JavaScript 입장에서는 문법 오류가 아닙니다. 실행은 될 수 있습니다. 다만 작성자가 원한 계산 흐름인지, 우연히 동작한 것인지 코드만 보고 바로 알기 어렵습니다.
TypeScript에서는 함수가 받아야 할 값의 형태를 코드에 적을 수 있습니다.
function getDiscountPrice(price: number, discount: number) {
return price - discount;
}
getDiscountPrice(30000, 5000);
getDiscountPrice("30000", "5000");
이 코드에서 두 번째 호출은 타입 검사 단계에서 문제가 됩니다. 함수는 number를 받겠다고 선언했는데 문자열을 넘겼기 때문입니다. 핵심은 TypeScript가 계산 방식을 바꾸는 것이 아닙니다. 코드를 실행하기 전에 “이 함수는 숫자를 받기로 했는데 문자열이 들어왔습니다”라고 알려주는 것입니다. 이런 경고가 있으면 화면에서 금액이 이상하게 표시된 뒤 원인을 찾는 것보다 훨씬 앞 단계에서 수정할 수 있습니다.
프론트엔드 학습 순서 안에서 TypeScript가 어디쯤 놓이는지 큰 흐름부터 잡고 싶다면 2026 프론트엔드 개발자 로드맵에서 HTML, CSS, JavaScript, React, Next.js, TypeScript가 이어지는 순서를 함께 확인할 수 있습니다.
JavaScript를 대체하는 언어가 아니다
TypeScript 파일을 작성해도 최종 실행 대상은 JavaScript입니다. 브라우저는 일반적으로 TypeScript 타입 문법을 직접 이해하지 않습니다. Node.js 프로젝트에서도 TypeScript를 그대로 실행하는 것이 아니라, 별도의 변환 과정이나 실행 도구를 거쳐 JavaScript로 바꾼 뒤 실행하는 흐름을 사용합니다. 그래서 .ts 파일을 작성한다고 해서 브라우저의 실행 원리가 새롭게 바뀌는 것은 아닙니다.
그래서 TypeScript를 배운다는 말은 JavaScript를 건너뛴다는 뜻이 아닙니다. 오히려 JavaScript의 변수, 함수, 객체, 배열, 조건문, 스코프, 비동기 흐름을 알고 있을수록 TypeScript도 더 쉽게 이해됩니다. TypeScript는 JavaScript의 기본 동작을 바꾸지 않고, 그 위에 타입 검사 기준을 얹습니다.
타입 검사를 추가한 JavaScript로 보는 것이 쉽다
TypeScript의 타입 문법은 코드의 의도를 설명하는 표시입니다. 함수 인자에 : number를 붙이면 “이 함수는 숫자를 받는 함수입니다”라는 약속을 코드에 남기는 것입니다. 객체 타입을 정의하면 “이 객체는 이런 property를 가져야 합니다”라는 기준을 만드는 것입니다.
이 기준이 있으면 에디터와 TypeScript 컴파일러가 코드를 미리 확인할 수 있습니다. 잘못된 값을 넘겼거나, 없는 property에 접근했거나, 반환값을 잘못 예상한 경우 실행 전에 경고를 받을 수 있습니다. 실무에서는 이 경고가 단순히 빨간 줄 하나로 끝나지 않습니다. 함수 사용법, 데이터 구조, 수정해야 할 위치를 코드 안에서 추적할 수 있게 해주는 단서가 됩니다.
JavaScript 코드가 TypeScript에서 경고가 되는 이유
![[기초 01] TypeScript란 무엇인가: JavaScript와 무엇이 다른가 2 JavaScript 문법 오류와 TypeScript 타입 오류와 런타임 오류 차이를 비교한 인포그래픽](https://blogflow.kr/wp-content/uploads/2026/06/03_body_image_2_compressed-8.jpg)
JavaScript에서는 문법만 맞으면 일단 실행까지 갈 수 있는 코드가 많습니다. 물론 실행 중에 오류가 날 수도 있고, 오류는 나지 않지만 의도와 다른 결과가 나올 수도 있습니다. TypeScript는 이런 문제 중 일부를 실행 전에 잡기 위해 타입 정보를 사용합니다. 이 차이를 이해하면 “왜 JavaScript에서는 됐는데 TypeScript에서는 빨간 줄이 생기지?”라는 의문이 줄어듭니다.
여기서 중요한 구분이 있습니다. TypeScript가 잡는 오류는 JavaScript 문법 오류와 다릅니다. 세미콜론 위치나 괄호 짝처럼 문법 자체가 틀린 문제도 있지만, TypeScript가 주로 도와주는 부분은 “문법은 맞지만 값의 형태가 기대와 다르다”는 문제입니다.
문법 오류와 타입 오류는 다르다
아래 코드는 괄호가 닫히지 않았으므로 JavaScript 문법 자체가 잘못된 예입니다.
console.log("hello";
반면 아래 코드는 문법만 보면 실행 가능한 JavaScript입니다.
const user = {
name: "해비",
age: 30
};
console.log(user.email);
JavaScript에서는 user.email이 없어도 문법 오류는 아닙니다. 결과는 undefined가 됩니다. 그런데 실제 화면에서 이메일을 출력해야 하는 상황이었다면 이 코드는 의도와 다릅니다. TypeScript에서는 객체의 타입을 기준으로 email이라는 property가 없다는 사실을 미리 알려줄 수 있습니다.
const user: {
name: string;
age: number;
} = {
name: "해비",
age: 30
};
console.log(user.email);
이 코드에서 TypeScript는 user 객체에 email property가 없다고 경고합니다. 실행해보고 화면이 깨진 뒤에 찾는 것이 아니라, 작성하는 단계에서 실수를 확인할 수 있는 것입니다.
실행 전 검사가 잡아주는 실수
TypeScript가 모든 버그를 없애주는 것은 아닙니다. 로직 자체가 잘못된 경우, 서버 데이터가 실제로 다르게 내려오는 경우, 사용자가 예상하지 못한 순서로 행동하는 경우까지 TypeScript가 자동으로 해결하지는 않습니다. TypeScript는 어디까지나 코드에 적힌 타입 기준으로 맞고 틀림을 검사합니다.
그럼에도 프론트엔드 작업에서는 이 차이가 꽤 큽니다. 함수가 어떤 값을 받아야 하는지, 컴포넌트 props가 어떤 구조인지, API 응답 객체에 어떤 property가 있어야 하는지를 코드에 남길 수 있기 때문입니다. 특히 파일이 많아지고 함수를 여러 곳에서 재사용할수록 타입 정보는 단순한 문법이 아니라 코드의 사용 설명서처럼 작동합니다. 다른 파일에서 함수를 호출할 때도 에디터가 필요한 인자와 반환값을 알려주므로, 코드를 열어보는 횟수도 줄어듭니다.
TypeScript와 JavaScript는 실행 방식이 어떻게 다른가
TypeScript를 이해할 때 반드시 짚고 넘어가야 할 부분이 있습니다. TypeScript의 타입은 개발 중 검사에 사용되지만, 최종 JavaScript 코드에는 그대로 남지 않습니다. 이 점을 모르면 TypeScript가 런타임에서도 값을 계속 검사한다고 오해하기 쉽습니다.
TypeScript 코드는 결국 JavaScript로 변환된다
아래 TypeScript 코드를 보겠습니다.
function formatUserName(name: string) {
return `${name}님`;
}
formatUserName("해비");
이 코드가 JavaScript로 변환되면 타입 표시는 사라집니다.
function formatUserName(name) {
return `${name}님`;
}
formatUserName("해비");
: string은 개발 중 타입 검사에 사용되는 정보입니다. 브라우저에서 실제로 실행되는 JavaScript 코드에는 이 타입 표시가 남지 않습니다. 그래서 TypeScript의 타입은 런타임 검증 도구라기보다, 실행 전에 코드를 점검하는 정적 검사 도구로 이해해야 합니다.
타입 정보는 실행 중에 남지 않는다
예를 들어 외부 API에서 받아온 데이터가 실제로 어떤 형태인지 확인하는 문제는 TypeScript만으로 완전히 해결되지 않습니다. 코드에 price: number라고 적어도, 서버가 문자열 "30000"을 내려주면 실행 중 데이터는 여전히 문자열입니다. TypeScript는 코드를 작성하는 단계에서 타입 기준을 확인하지만, 네트워크를 통해 들어온 실제 값을 자동으로 변환하거나 보장하지는 않습니다.
따라서 TypeScript를 사용할 때도 외부 데이터는 필요에 따라 런타임 검증을 따로 고려해야 합니다. 이 글에서는 그 부분까지 깊게 들어가지는 않습니다. 기초 단계에서는 먼저 “TypeScript 타입은 실행 전에 검사되고, 실행 코드에서는 사라진다”는 기준만 잡으면 됩니다.
TypeScript가 런타임 동작을 바꾸지는 않는다
TypeScript는 JavaScript의 이상한 동작을 전부 새롭게 고치는 언어가 아닙니다. 예를 들어 JavaScript의 형 변환, truthy/falsy 판단, 배열과 객체의 참조 동작 같은 기본 규칙은 그대로 유지됩니다. TypeScript를 쓰더라도 JavaScript의 실행 원리를 모르면 예상과 다른 결과를 만날 수 있습니다.
이 때문에 TypeScript 입문은 JavaScript 기초 위에서 진행하는 것이 자연스럽습니다. TypeScript가 추가하는 것은 실행 방식 자체가 아니라, 실행 전에 코드를 더 엄격하게 확인하는 층입니다.
TypeScript를 쓰면 개발할 때 무엇이 달라지는가
TypeScript의 효과는 문법을 많이 아는 순간보다, 코드를 수정하거나 재사용할 때 더 분명하게 느껴집니다. 변수와 함수가 많아질수록 “이 값이 어떤 형태였지?”를 계속 확인하게 되는데, TypeScript는 그 기준을 코드 안에 남기게 해줍니다. 특히 화면을 만든 뒤 API 연결, 상태 관리, 컴포넌트 분리로 넘어가면 타입 정보가 코드 이동 경로를 따라다니는 안내선처럼 작동합니다.
함수 인자와 반환값을 더 명확하게 본다
JavaScript에서 함수는 어떤 값이든 받을 수 있습니다. 이것이 자유롭다는 장점도 있지만, 프로젝트가 커질수록 호출하는 쪽과 구현하는 쪽의 약속이 흐려지기 쉽습니다.
function createOrderMessage(productName: string, quantity: number) {
return `${productName} ${quantity}개가 주문되었습니다.`;
}
createOrderMessage("키보드", 2);
createOrderMessage("키보드", "2");
이 예시에서 두 번째 호출은 문자열 "2"를 넘기고 있습니다. 화면에는 비슷하게 보일 수 있지만, 함수는 숫자를 기준으로 작성되어 있습니다. TypeScript는 이런 차이를 호출 단계에서 알려줍니다. 장바구니 수량, 결제 금액, 페이지 번호처럼 숫자로 계산해야 하는 값은 문자열로 들어오면 이후 계산에서 문제가 커질 수 있습니다. 함수 호출 위치에서 인자 타입이 맞지 않을 때는 나중에 TypeScript No overload matches this call 오류처럼 더 구체적인 오류 메시지로 이어질 수 있습니다.
객체 property 오타를 더 빨리 발견한다
프론트엔드 코드는 객체를 많이 다룹니다. 사용자 정보, 상품 정보, 게시글 정보, API 응답 데이터는 대부분 객체 형태로 들어옵니다. 이때 property 이름을 잘못 쓰면 화면에는 빈 값이 나오거나, 특정 조건에서만 오류가 발생할 수 있습니다.
type Product = {
title: string;
price: number;
isSoldOut: boolean;
};
const product: Product = {
title: "무선 마우스",
price: 29000,
isSoldOut: false
};
console.log(product.salePrice);
이 코드에서 salePrice는 Product 타입에 없습니다. JavaScript였다면 undefined가 나올 수 있지만, TypeScript는 작성 단계에서 존재하지 않는 property 접근이라고 알려줍니다. 이런 경고는 단순 오타를 줄이는 데도 도움이 되고, 객체 구조가 바뀌었을 때 수정해야 할 위치를 찾는 데도 도움이 됩니다.
API 응답 구조를 코드에서 확인하기 쉬워진다
실제 프론트엔드 작업에서는 API 응답 데이터를 화면에 뿌리는 일이 많습니다. 이때 응답 객체가 어떤 property를 갖는지 명확하지 않으면, 화면을 만들면서 계속 콘솔을 찍어보거나 문서를 오가며 확인해야 합니다.
type UserProfile = {
id: number;
nickname: string;
email: string;
};
function renderProfile(user: UserProfile) {
return `${user.nickname} / ${user.email}`;
}
이렇게 타입을 정해두면 renderProfile 함수는 어떤 형태의 사용자 데이터를 기대하는지 바로 드러납니다. 협업 상황에서도 이 함수에 어떤 값을 넘겨야 하는지 코드만 보고 확인할 수 있습니다. 나중에 API 응답 타입과 화면에서 기대하는 타입이 어긋나면 TypeScript Type is not assignable to type 오류처럼 실제 오류 메시지를 기준으로 원인을 추적하게 됩니다.
처음부터 어렵게 외우지 않아도 되는 것들
TypeScript를 처음 공부할 때 가장 흔한 실수는 처음부터 모든 문법을 한 번에 외우려는 것입니다. 기본 타입을 조금 본 뒤 바로 제네릭, 조건부 타입, 유틸리티 타입, 설정 파일까지 한꺼번에 보면 TypeScript가 실제보다 훨씬 어렵게 느껴집니다.
tsconfig와 최신 버전 변화는 뒤에서 다뤄도 된다
TypeScript 프로젝트에는 보통 tsconfig.json 파일이 있습니다. 이 파일은 TypeScript가 어떤 기준으로 코드를 검사하고 변환할지 정하는 설정 파일입니다. 다만 입문 첫 단계에서 설정 옵션을 모두 이해할 필요는 없습니다.
처음에는 타입이 무엇인지, 함수와 객체에서 타입이 어떻게 작동하는지, 오류 메시지를 어떻게 읽어야 하는지부터 잡는 것이 우선입니다. 버전별 설정 변화나 tsconfig 정리는 기본 개념을 잡은 뒤 TypeScript 6.0 업데이트처럼 마이그레이션 흐름을 다루는 글에서 따로 확인하는 편이 자연스럽습니다.
제네릭과 조건부 타입은 기초 이후에 봐도 된다
TypeScript에는 강력한 타입 설계 문법이 많습니다. 제네릭, 조건부 타입, mapped type, infer 같은 문법은 라이브러리 타입을 읽거나 복잡한 공통 타입을 만들 때 필요합니다. 하지만 TypeScript를 처음 배우는 단계에서 이 문법부터 들어가면 타입 검사의 기본 목적을 놓치기 쉽습니다.
기초 단계에서는 “이 값은 문자열이다”, “이 함수는 숫자를 받는다”, “이 객체에는 이런 property가 있어야 한다” 정도의 기준부터 충분히 익히면 됩니다. 복잡한 타입 문법은 나중에 실제로 필요해지는 지점에서 연결해도 늦지 않습니다.
중요한 것은 타입 오류를 읽는 감각이다
TypeScript를 잘 다루려면 모든 타입 문법을 외우는 것보다 오류 메시지가 말하는 방향을 읽는 감각이 중요합니다. 오류 메시지는 보통 “현재 값의 타입”과 “기대하는 타입”이 다르다는 식으로 알려줍니다. 이 구조를 이해하면 낯선 오류를 만나도 무작정 as any로 덮기 전에 원인을 찾을 수 있습니다. as any는 빨간 줄을 없애는 데는 빠르지만, 타입 검사가 알려주려던 단서를 같이 지워버릴 수 있습니다.
처음에는 오류 메시지가 길고 딱딱하게 느껴질 수 있습니다. 그래도 대부분의 타입 오류는 “값의 형태가 기대한 형태와 다르다”는 문제로 돌아옵니다. 그래서 TypeScript 기초 학습은 타입 이름을 외우는 것보다, 값의 형태를 코드로 설명하는 연습에 가깝습니다. 어떤 값이 들어올 수 있는지, 어떤 값은 들어오면 안 되는지 경계선을 세우는 과정이라고 보면 됩니다.
다음 글로 이어지는 TypeScript 학습 순서
![[기초 01] TypeScript란 무엇인가: JavaScript와 무엇이 다른가 3 TypeScript 기초 학습 흐름을 타입 추론과 타입 호환성 오류와 narrowing 순서로 정리한 학습 맵](https://blogflow.kr/wp-content/uploads/2026/06/04_body_image_3_compressed.jpg)
이번 글에서 잡아야 할 결론은 단순합니다. TypeScript는 JavaScript를 대체하는 언어가 아닙니다. JavaScript 코드에 타입 검사 기준을 더해, 실행 전에 흔한 실수를 더 빨리 발견하게 해주는 도구입니다.
여기까지 이해하면 TypeScript의 첫 기준은 잡힌 것입니다. JavaScript 코드를 작성하되, 값의 형태와 함수의 약속을 실행 전에 확인하는 도구로 TypeScript를 사용하는 것입니다. 이제 남는 질문은 “그 타입을 개발자가 전부 직접 적어야 하는가?”입니다.
다음 단계에서는 “그럼 타입을 매번 직접 적어야 하는가?”라는 질문으로 넘어가야 합니다. TypeScript는 많은 경우 값을 보고 타입을 스스로 추론합니다. 예를 들어 const name = "해비"라고 작성하면 TypeScript는 이 값이 문자열이라는 사실을 어느 정도 판단할 수 있습니다.
반대로 함수 인자, 외부 API 응답, 재사용되는 객체 구조처럼 코드의 의도를 더 분명히 남겨야 하는 곳에서는 타입을 직접 적는 것이 필요합니다. 그래서 다음 글에서는 타입 추론과 타입 명시를 기준으로, TypeScript가 언제 알아서 판단하고 언제 개발자가 타입을 적어야 하는지 정리하는 흐름으로 이어가면 됩니다.
그다음에는 타입 호환성 오류를 보면 됩니다. TypeScript를 쓰다 보면 “이 타입은 저 타입에 할당할 수 없다”는 식의 오류를 자주 만나게 됩니다. 이 오류는 TypeScript가 까다로워서 생기는 문제가 아니라, 값의 형태와 기대하는 타입이 맞지 않는다는 신호입니다.
마지막으로 narrowing을 이해하면 조건문 안에서 타입이 어떻게 좁혀지는지 볼 수 있습니다. 값이 문자열일 수도 있고 숫자일 수도 있을 때, 조건문을 통해 TypeScript에게 현재 값의 형태를 더 구체적으로 알려주는 방식입니다.
TypeScript 기초는 어려운 문법을 많이 외우는 방향보다, JavaScript 코드의 의도를 타입으로 설명하고 오류 메시지를 읽는 방향으로 접근하는 것이 좋습니다. 이 기준을 잡고 나면 이후에 나오는 타입 추론, 타입 명시, 타입 호환성, narrowing은 서로 끊어진 문법이 아니라 하나의 흐름으로 연결됩니다.