✅ 들어가며
취업 준비 시절, 나는 타입스크립트까지 제대로 공부하지 못한 채 취업에 성공했다.
당시에는 타입스크립트가 프론트엔드 개발을 더 안정적이고 확실하게 만들어주는 도구라는 정도로만 알고 있었다.
그러나 현업에서 자바스크립트로 개발을 하면서, 타입스크립트의 필요성을 몸소 체감하는 순간이 많았다.
함수의 파라미터는 숫자형이어야 했지만, 라이브러리 반환값은 문자열인 숫자로 반환되는 바람에 오류가 발생한 적이 있다.
이 오류의 원인을 파악하는 데 시간이 꽤 걸렸던 기억이 난다.
또한, 개발 완료 후 코드를 실행했을 때 콘솔에 런타임 에러가 발생하곤 했고, 그 에러를 해결하는 데 많은 시간을 쏟았다.
만약 처음부터 타입 가드를 적용해 undefined.length 같은 상황을 처리했다면,
TypeError: Cannot read property of undefined 이런 런타임 오류가 발생하는 문제를 예방할 수 있었을 것이다.
현재 나는 타입스크립트를 잘 활용하기 위해 TypeScript Challenge를 풀며 하나씩 학습을 이어가고 있다.
타입스크립트가 가져다주는 이점을 더 깊이 이해하고, 이를 통해 더 안정적이고 효율적인 코드를 작성하고자 한다.
✅ TypeScript와 Javascript
TypeScript는 JavaScript의 Superset(상위 확장)이다.
기존 JavaScript 코드를 그대로 사용하면서, JavaScript에 정적 타입 시스템을 덧붙여 개발자 경험을 향상시킨 것이다.

💡인터프리터와 컴파일러
일단 ts와 js의 차이를 알기 위한 배경지식으로 "인터프리터와 컴파일러"를 이해해야 한다.
구분 | 인터프리터 | 컴파일러 |
작동 방식 | 명령어 단위로 번역하며 즉시 실행 | 전체 코드를 한 번에 번역 후 실행 |
오류 발견 시점 | 실행 중 (런타임) | 컴파일 시 (실행 전) |
장점 | - 코드 수정 후 즉시 실행 가능 - 빠른 피드백 가능 |
- 실행 속도가 빠름 - 사전 오류 검출 가능 |
단점 | - 실행 속도가 느림 - 런타임 오류 발생 가능 |
- 초기 컴파일 시간 소요 - 잦은 수정 시 비효율적 |
대표 언어 | JavaScript, Python 등 | TypeScript, C, Java 등 |
인터프리터 (Interpreter)
- 소스 코드를 한 줄씩 읽어 즉시 실행하는 방식
- 컴파일러와 달리 전체 코드를 한번에 번역하지 않고, 소스코드 명령어 한줄마다 기계어로 번역하여 바로 실행되는 것이다.
- 장점 : 번역과 실행이 동시에 이뤄져 즉각적인 결과 확인 가능 (실행 즉시 번역됨)(잦은 코드 수정시 유리함).
- 단점1 : 한번에 한 문장씩 번역후 실행시키기 때문에 실행 속도가 느리다.
- 단점2 : 코드 실행 중에만 오류를 발견할 수 있음.
컴파일러 (Compiler)
- 소스 코드를 한 번에 스캔해 기계어로 변환(번역)한 실행 파일을 생성하는 방식
- 변환(컴파일) 단계에서 문법,타입 오류 확인하며 변환된 파일이 실행된다.
- 장점1 : 실행 전에 모든 오류 검출 (코드 컴파일 하는 과정에서 오류 발생하게된다),
- 장점2 : 빠른 실행 속도 (처음에 한번에 기계어로 컴파일 해놔서 실행이 빠르다)
- 단점: 초기 번역 시간이 길고 잦은 수정에 비효율적.
(참조 : 컴파일러(compiler)와 인터프리터(interpreter)의 차이)
💡인터프리터 언어 vs 컴파일러 언어
1. JavaScript (인터프리터 언어)
JavaScript는 인터프리터 방식으로 실행되기 때문에, 코드를 실행하는 과정에서 오류를 발견한다.
이런 방식은 코드 실행 전에 오류를 사전에 방지하기 어렵다.
2. TypeScript (컴파일 언어)
TypeScript는 컴파일러를 통해 JavaScript로 변환되기 전에 코드의 문법과 타입을 검증한다.
컴파일 단계에서 오류를 미리 발견하므로, 런타임에서 발생할 수 있는 문제를 줄일 수 있게된다.
💡동적 타입 언어 vs 정적 타입 언어
1. JavaScript (동적 타입 언어)
1) 타입 결정 시점 : 런타임시. 변수에 어떤 데이터가 들어갈지는 실행 중에 확인된다.
2) 안정성 : 낮음 (런타임 오류 가능)
개발 단계에서 오류를 확인하기 어렵다.
프로그램 실행 중에야 오류를 발견할 수 있어 사용자에게 영향을 미칠 수 있습니다.
3) 타입 변경 : 코드 실행시 자유로운 타입 변경 허용
function sum(a, b) {
return a + b;
}
sum(1, 2); // 3
sum("x", "y"); // 'xy' (문자열 결합)
2. TypeScript (정적 타입 언어)
1) 타입 결정 시점 : 컴파일시. 변수의 타입이 런타임 이전의 컴파일 단계에서 결정된다.
2) 안정성 : 높은 (컴파일시 오류 검출)
3) 타입 변경 : 타입 변경시 오류 발생
function sum(a: number, b: number): number {
return a + b;
}
sum("x", "y");
// error TS2345: Argument of type '"x"' is not assignable to parameter of type 'number'.
// 컴파일 에러: 'string' 타입은 'number' 타입에 할당할 수 없음
✅ TypeScript를 사용하는 이유
1. 런타임 에러 감소로 안정성 강화
JavaScript는 동적 타입 언어로, 실행 중 오류가 발생할 가능성이 크다.
이로인해 사용자에게 그 오류가 그대로 노출될 위험이 있다.
function greetUser(userName) {
console.log("Hello, " + userName.toUpperCase() + "!");
}
// 올바른 호출
greetUser("Alice"); // 출력: Hello, ALICE!
// 잘못된 호출 - userName에 undefined가 전달됨
greetUser(); // 런타임 오류 발생: TypeError: Cannot read properties of undefined (reading 'toUpperCase')
// 잘못된 호출 - userName에 숫자가 전달됨
greetUser(123); // 런타임 오류 발생: TypeError: userName.toUpperCase is not a function
반면, TypeScript는 컴파일 단계에서 오류를 발견해 실행 전 수정할 수 있다.
function add(a: number, b: number): number {
return a + b;
}
add(10, "20"); // 컴파일 에러 발생: '20'은 string 타입
2. 개발자 경험(DX) 향상
TypeScript는 IDE의 자동완성, 타입 추론, 코드 탐색 기능을 강화하여 개발 생산성을 높인다.
이를 통해 파라미터의 형태나 타입을 vscode에서 즉시 확인할 수 있어 코드 작성 속도가 빨라진다.
나는 이 점이 개발하면서 정말 편했던 것 같다.
const user = {
name: "Alice",
age: 25,
};
console.log(user.); // 자동완성을 통해 'name'과 'age'를 빠르게 확인 가능
3. 유지보수성 증가
- 타입을 명확히 선언하여, 의도치 않게 타입을 변경하는 문제를 방지할 수 있다.
- 디버깅을 수월하게 할 수 있다 : 개발시 vscode에서 오류를 바로 알려주기 떄문에 문제를 빠르게 파악할 수 있다.
- 협업시 인터페이스를 정의하는데 도움이 되기도 한다.
interface User {
id: number;
name: string;
email?: string; // 선택적 속성
}
function createUser(user: User): void {
console.log(user);
}
createUser({ id: 1, name: "John" }); // 올바른 호출
createUser({ id: 2 }); // 컴파일 에러 발생: 'name' 속성 누락
createUser({ id: "3" }); // 컴파일 에러 발생: 'string' 형식은 'number' 형식에 할당할 수 없습니다.
✅ 타입스크립트 컴파일러 동작원리
npx tsc note.ts를 실행하면 note.ts 파일이 note.js로 변환이 된다.
단순히 명령어만 실행할 줄 알았는데 이게 어떤 원리로 인해 발생하는건지 알아보자!
TypeScript의 컴파일러(tsc)는 고급 프로그래밍 언어인 TypeScript 코드를 브라우저나 Node.js에서 실행 가능한 JavaScript 코드로 변환하는 역할을 한다. 이 과정은 크게 4단계로 이루어진다.
1. 파일 로드 및 파싱
TypeScript 컴파일러는 프로젝트의 설정 파일(tsconfig.json)을 읽어들인 뒤, 컴파일 대상 파일을 식별한다.
그런 다음, TypeScript 파일(.ts, .tsx)을 로드하고 각 파일을 파싱하여 추상 구문 트리(AST, Abstract Syntax Tree)를 생성한다.
우리가 작성한 코드는 컴파일러에게는 단순한 텍스트에 불과하기 때문에 AST로 파싱하는 것이다.
AST는 우리가 작성한 코드를 컴파일러가 이해할 수 있는 형태로 구조화한 트리이다.
AST는 이후 과정에서 타입 검사 및 변환 작업에 활용된다.
// 1. typescript코드
const add = (a: number, b: number): number => {
return a + b;
};
// 2. 위 코드를 컴파일러가 읽으면, 다음과 같은 AST를 생성한다.
Program
├── VariableDeclaration
│ ├── Identifier: "add"
│ ├── ArrowFunctionExpression
│ ├── Parameters
│ │ ├── Identifier: "a" (type: number)
│ │ ├── Identifier: "b" (type: number)
│ ├── ReturnType: number
│ ├── Body
│ ├── ReturnStatement
│ ├── BinaryExpression
│ ├── Identifier: "a"
│ ├── Operator: "+"
│ ├── Identifier: "b"
2. 타입 검사
TypeScript의 핵심 기능인 정적 타입 검사가 이 단계에서 이루어진다.
컴파일러는 생성된 AST를 기반으로 각 변수, 함수, 객체 등의 타입을 확인하게 된다.
- 타입 오류가 발견되면 컴파일을 중단하고 해당 오류를 보고한다.
3. js코드 생성
타입 검사가 완료된 후, TypeScript 컴파일러는 AST를 변환하여 JavaScript 코드로 출력한다.
TypeScript 코드에서 작성한 타입 정보는 JavaScript 코드에는 포함되지 않고, 실행 가능한 순수 JavaScript 코드만 생성된다.
- 컴파일러 옵션(target)에 따라 출력되는 JavaScript 코드의 표준(ES5, ES6 등)이 결정된다.
// tsconfig.json
{"target": "es2016", ...}
4. 출력과 번들링
(참고 : https://develog-yeon.tistory.com/35)
✅ 결론
타입스크립트를 사용해보니, “한 번 써보면 다시는 안 쓸 수 없다”는 말이 뭔지 확 와닿았다.
지난 ts없이 개발하던 회사 프로젝트에서는 변수의 타입이 확실치 않아 불안감이 있었다.
혹여 라이브러리가 숫자를 문자열로 응답하지는 않을까 싶어 typeof로 확인해야 했고,
또 데이터 값이 undefined일 때 가드 처리를 빼먹지는 않았을까 하는 걱정이 항상 따라다녔다.
하지만 타입스크립트를 사용하면서 이런 고민이 크게 해소되었다.
타입이 명확화되있다 보니 어떤 값이 들어와야 하는지 예측이 가능해졌고,
또한 런타임 에러를 미리 방지하며 개발을 한다는 점에 안도감도 들었다.
타입스크립트를 사용하지 않았던 과거의 경험 덕분에, 지금은 TS의 필요성과 강력함을 더욱 체감하고 있다.
'프론트엔드 > Typescript' 카테고리의 다른 글
[ts] 제네릭 (0) | 2023.12.22 |
---|
✅ 들어가며
취업 준비 시절, 나는 타입스크립트까지 제대로 공부하지 못한 채 취업에 성공했다.
당시에는 타입스크립트가 프론트엔드 개발을 더 안정적이고 확실하게 만들어주는 도구라는 정도로만 알고 있었다.
그러나 현업에서 자바스크립트로 개발을 하면서, 타입스크립트의 필요성을 몸소 체감하는 순간이 많았다.
함수의 파라미터는 숫자형이어야 했지만, 라이브러리 반환값은 문자열인 숫자로 반환되는 바람에 오류가 발생한 적이 있다.
이 오류의 원인을 파악하는 데 시간이 꽤 걸렸던 기억이 난다.
또한, 개발 완료 후 코드를 실행했을 때 콘솔에 런타임 에러가 발생하곤 했고, 그 에러를 해결하는 데 많은 시간을 쏟았다.
만약 처음부터 타입 가드를 적용해 undefined.length 같은 상황을 처리했다면,
TypeError: Cannot read property of undefined 이런 런타임 오류가 발생하는 문제를 예방할 수 있었을 것이다.
현재 나는 타입스크립트를 잘 활용하기 위해 TypeScript Challenge를 풀며 하나씩 학습을 이어가고 있다.
타입스크립트가 가져다주는 이점을 더 깊이 이해하고, 이를 통해 더 안정적이고 효율적인 코드를 작성하고자 한다.
✅ TypeScript와 Javascript
TypeScript는 JavaScript의 Superset(상위 확장)이다.
기존 JavaScript 코드를 그대로 사용하면서, JavaScript에 정적 타입 시스템을 덧붙여 개발자 경험을 향상시킨 것이다.

💡인터프리터와 컴파일러
일단 ts와 js의 차이를 알기 위한 배경지식으로 "인터프리터와 컴파일러"를 이해해야 한다.
구분 | 인터프리터 | 컴파일러 |
작동 방식 | 명령어 단위로 번역하며 즉시 실행 | 전체 코드를 한 번에 번역 후 실행 |
오류 발견 시점 | 실행 중 (런타임) | 컴파일 시 (실행 전) |
장점 | - 코드 수정 후 즉시 실행 가능 - 빠른 피드백 가능 |
- 실행 속도가 빠름 - 사전 오류 검출 가능 |
단점 | - 실행 속도가 느림 - 런타임 오류 발생 가능 |
- 초기 컴파일 시간 소요 - 잦은 수정 시 비효율적 |
대표 언어 | JavaScript, Python 등 | TypeScript, C, Java 등 |
인터프리터 (Interpreter)
- 소스 코드를 한 줄씩 읽어 즉시 실행하는 방식
- 컴파일러와 달리 전체 코드를 한번에 번역하지 않고, 소스코드 명령어 한줄마다 기계어로 번역하여 바로 실행되는 것이다.
- 장점 : 번역과 실행이 동시에 이뤄져 즉각적인 결과 확인 가능 (실행 즉시 번역됨)(잦은 코드 수정시 유리함).
- 단점1 : 한번에 한 문장씩 번역후 실행시키기 때문에 실행 속도가 느리다.
- 단점2 : 코드 실행 중에만 오류를 발견할 수 있음.
컴파일러 (Compiler)
- 소스 코드를 한 번에 스캔해 기계어로 변환(번역)한 실행 파일을 생성하는 방식
- 변환(컴파일) 단계에서 문법,타입 오류 확인하며 변환된 파일이 실행된다.
- 장점1 : 실행 전에 모든 오류 검출 (코드 컴파일 하는 과정에서 오류 발생하게된다),
- 장점2 : 빠른 실행 속도 (처음에 한번에 기계어로 컴파일 해놔서 실행이 빠르다)
- 단점: 초기 번역 시간이 길고 잦은 수정에 비효율적.
(참조 : 컴파일러(compiler)와 인터프리터(interpreter)의 차이)
💡인터프리터 언어 vs 컴파일러 언어
1. JavaScript (인터프리터 언어)
JavaScript는 인터프리터 방식으로 실행되기 때문에, 코드를 실행하는 과정에서 오류를 발견한다.
이런 방식은 코드 실행 전에 오류를 사전에 방지하기 어렵다.
2. TypeScript (컴파일 언어)
TypeScript는 컴파일러를 통해 JavaScript로 변환되기 전에 코드의 문법과 타입을 검증한다.
컴파일 단계에서 오류를 미리 발견하므로, 런타임에서 발생할 수 있는 문제를 줄일 수 있게된다.
💡동적 타입 언어 vs 정적 타입 언어
1. JavaScript (동적 타입 언어)
1) 타입 결정 시점 : 런타임시. 변수에 어떤 데이터가 들어갈지는 실행 중에 확인된다.
2) 안정성 : 낮음 (런타임 오류 가능)
개발 단계에서 오류를 확인하기 어렵다.
프로그램 실행 중에야 오류를 발견할 수 있어 사용자에게 영향을 미칠 수 있습니다.
3) 타입 변경 : 코드 실행시 자유로운 타입 변경 허용
function sum(a, b) {
return a + b;
}
sum(1, 2); // 3
sum("x", "y"); // 'xy' (문자열 결합)
2. TypeScript (정적 타입 언어)
1) 타입 결정 시점 : 컴파일시. 변수의 타입이 런타임 이전의 컴파일 단계에서 결정된다.
2) 안정성 : 높은 (컴파일시 오류 검출)
3) 타입 변경 : 타입 변경시 오류 발생
function sum(a: number, b: number): number {
return a + b;
}
sum("x", "y");
// error TS2345: Argument of type '"x"' is not assignable to parameter of type 'number'.
// 컴파일 에러: 'string' 타입은 'number' 타입에 할당할 수 없음
✅ TypeScript를 사용하는 이유
1. 런타임 에러 감소로 안정성 강화
JavaScript는 동적 타입 언어로, 실행 중 오류가 발생할 가능성이 크다.
이로인해 사용자에게 그 오류가 그대로 노출될 위험이 있다.
function greetUser(userName) {
console.log("Hello, " + userName.toUpperCase() + "!");
}
// 올바른 호출
greetUser("Alice"); // 출력: Hello, ALICE!
// 잘못된 호출 - userName에 undefined가 전달됨
greetUser(); // 런타임 오류 발생: TypeError: Cannot read properties of undefined (reading 'toUpperCase')
// 잘못된 호출 - userName에 숫자가 전달됨
greetUser(123); // 런타임 오류 발생: TypeError: userName.toUpperCase is not a function
반면, TypeScript는 컴파일 단계에서 오류를 발견해 실행 전 수정할 수 있다.
function add(a: number, b: number): number {
return a + b;
}
add(10, "20"); // 컴파일 에러 발생: '20'은 string 타입
2. 개발자 경험(DX) 향상
TypeScript는 IDE의 자동완성, 타입 추론, 코드 탐색 기능을 강화하여 개발 생산성을 높인다.
이를 통해 파라미터의 형태나 타입을 vscode에서 즉시 확인할 수 있어 코드 작성 속도가 빨라진다.
나는 이 점이 개발하면서 정말 편했던 것 같다.
const user = {
name: "Alice",
age: 25,
};
console.log(user.); // 자동완성을 통해 'name'과 'age'를 빠르게 확인 가능
3. 유지보수성 증가
- 타입을 명확히 선언하여, 의도치 않게 타입을 변경하는 문제를 방지할 수 있다.
- 디버깅을 수월하게 할 수 있다 : 개발시 vscode에서 오류를 바로 알려주기 떄문에 문제를 빠르게 파악할 수 있다.
- 협업시 인터페이스를 정의하는데 도움이 되기도 한다.
interface User {
id: number;
name: string;
email?: string; // 선택적 속성
}
function createUser(user: User): void {
console.log(user);
}
createUser({ id: 1, name: "John" }); // 올바른 호출
createUser({ id: 2 }); // 컴파일 에러 발생: 'name' 속성 누락
createUser({ id: "3" }); // 컴파일 에러 발생: 'string' 형식은 'number' 형식에 할당할 수 없습니다.
✅ 타입스크립트 컴파일러 동작원리
npx tsc note.ts를 실행하면 note.ts 파일이 note.js로 변환이 된다.
단순히 명령어만 실행할 줄 알았는데 이게 어떤 원리로 인해 발생하는건지 알아보자!
TypeScript의 컴파일러(tsc)는 고급 프로그래밍 언어인 TypeScript 코드를 브라우저나 Node.js에서 실행 가능한 JavaScript 코드로 변환하는 역할을 한다. 이 과정은 크게 4단계로 이루어진다.
1. 파일 로드 및 파싱
TypeScript 컴파일러는 프로젝트의 설정 파일(tsconfig.json)을 읽어들인 뒤, 컴파일 대상 파일을 식별한다.
그런 다음, TypeScript 파일(.ts, .tsx)을 로드하고 각 파일을 파싱하여 추상 구문 트리(AST, Abstract Syntax Tree)를 생성한다.
우리가 작성한 코드는 컴파일러에게는 단순한 텍스트에 불과하기 때문에 AST로 파싱하는 것이다.
AST는 우리가 작성한 코드를 컴파일러가 이해할 수 있는 형태로 구조화한 트리이다.
AST는 이후 과정에서 타입 검사 및 변환 작업에 활용된다.
// 1. typescript코드
const add = (a: number, b: number): number => {
return a + b;
};
// 2. 위 코드를 컴파일러가 읽으면, 다음과 같은 AST를 생성한다.
Program
├── VariableDeclaration
│ ├── Identifier: "add"
│ ├── ArrowFunctionExpression
│ ├── Parameters
│ │ ├── Identifier: "a" (type: number)
│ │ ├── Identifier: "b" (type: number)
│ ├── ReturnType: number
│ ├── Body
│ ├── ReturnStatement
│ ├── BinaryExpression
│ ├── Identifier: "a"
│ ├── Operator: "+"
│ ├── Identifier: "b"
2. 타입 검사
TypeScript의 핵심 기능인 정적 타입 검사가 이 단계에서 이루어진다.
컴파일러는 생성된 AST를 기반으로 각 변수, 함수, 객체 등의 타입을 확인하게 된다.
- 타입 오류가 발견되면 컴파일을 중단하고 해당 오류를 보고한다.
3. js코드 생성
타입 검사가 완료된 후, TypeScript 컴파일러는 AST를 변환하여 JavaScript 코드로 출력한다.
TypeScript 코드에서 작성한 타입 정보는 JavaScript 코드에는 포함되지 않고, 실행 가능한 순수 JavaScript 코드만 생성된다.
- 컴파일러 옵션(target)에 따라 출력되는 JavaScript 코드의 표준(ES5, ES6 등)이 결정된다.
// tsconfig.json
{"target": "es2016", ...}
4. 출력과 번들링
(참고 : https://develog-yeon.tistory.com/35)
✅ 결론
타입스크립트를 사용해보니, “한 번 써보면 다시는 안 쓸 수 없다”는 말이 뭔지 확 와닿았다.
지난 ts없이 개발하던 회사 프로젝트에서는 변수의 타입이 확실치 않아 불안감이 있었다.
혹여 라이브러리가 숫자를 문자열로 응답하지는 않을까 싶어 typeof로 확인해야 했고,
또 데이터 값이 undefined일 때 가드 처리를 빼먹지는 않았을까 하는 걱정이 항상 따라다녔다.
하지만 타입스크립트를 사용하면서 이런 고민이 크게 해소되었다.
타입이 명확화되있다 보니 어떤 값이 들어와야 하는지 예측이 가능해졌고,
또한 런타임 에러를 미리 방지하며 개발을 한다는 점에 안도감도 들었다.
타입스크립트를 사용하지 않았던 과거의 경험 덕분에, 지금은 TS의 필요성과 강력함을 더욱 체감하고 있다.
'프론트엔드 > Typescript' 카테고리의 다른 글
[ts] 제네릭 (0) | 2023.12.22 |
---|