1. 타입스크립트란 무엇이며 왜 필요한가?
1.1 자바스크립트의 슈퍼셋(확장된 언어)
타입스크립트는 흔히 다음 문장으로 정의됩니다.
“TypeScript is JavaScript with syntax for types.”
즉, 자바스크립트 문법 위에 타입 문법만 얹은 언어입니다. 기존 자바스크립트 코드는 그대로 동작하며, 여기에 타입 정보를 추가함으로써 더 안전한 코드를 작성할 수 있습니다.
중요한 점은 타입스크립트 자체가 새로운 런타임을 만들지 않는다는 것입니다. 모든 타입스크립트 코드는 결국 자바스크립트로 변환(트랜스파일)되어 실행됩니다.
1.2 런타임 에러를 “미리” 막기
자바스크립트는 동적 타입 언어이기 때문에 다음과 같은 코드는 실행 전까지 문제를 알기 어렵습니다.
return a + b } sum('1', 2) // "12"
타입스크립트는 이런 문제를 빌드 타임에 바로 알려줍니다.
function sum(a: number, b: number) { return a + b } sum('1', 2) // ❌ 컴파일 에러
👉 실행해 보기 전에 “이 코드는 위험하다”고 알려주는 것이 타입스크립트의 가장 큰 장점입니다.
2. 효과적인 타입스크립트 활용 팁
타입스크립트를 단순히 “에러 안 나게 하는 도구”로만 쓰기에는 너무 아깝습니다. 교안에서 강조한 실무에서 중요한 개념들을 정리해보면 다음과 같습니다.
2.1 any 대신 unknown 사용하기
any는 타입스크립트의 모든 보호 장치를 꺼버리는 타입입니다.
let value: any value.toUpperCase() // ❌ 에러 없음 (위험)
반면 unknown은 “아직 모르는 값”을 의미합니다.
let value: unknown value.toUpperCase() // ❌ 사용 불가
unknown은 타입을 확인하기 전까지 사용할 수 없도록 강제합니다.
if (typeof value === 'string') {
value.toUpperCase() // ✅ 안전
}
👉 교안에서 unknown을 강조하는 이유는 “타입을 쓰는 쪽에서 책임 있게 좁히도록 강제하기 위해서”입니다.
2.2 타입 가드(Type Guard)를 통한 타입 좁히기
unknown이나 여러 타입이 섞인 상황에서는 타입 가드가 필수입니다.
typeof: 기본 타입 판별instanceof: 클래스 기반 판별 (에러 처리에서 매우 중요)in: 객체의 속성 존재 여부 판별
특히 catch (e) 구문에서 e는 기본적으로 unknown이기 때문에, 다음과 같은 패턴이 교안에서 강조됩니다.
if (e instanceof UnauthorizedError) { // 이 블록 안에서 e는 UnauthorizedError }
👉 이는 런타임 안전성 + 타입스크립트 타입 추론을 동시에 만족시키는 설계입니다.
2.3 제네릭(Generic)과 useState의 관계
제네릭은 “타입을 나중에 결정하는 함수/타입”입니다.
function getFirstAndLast<T>(list: T[]): [T, T] {
return [list[0], list[list.length - 1]]
}
이 함수는 숫자 배열이든, 문자열 배열이든 동일하게 동작합니다. 리액트의 useState가 제네릭을 사용하는 이유도 동일합니다.
const [state, setState] = useState<string>('')
- 상태의 타입을 명확하게 고정
undefined로 추론되는 문제 방지- 이후 상태 업데이트 시 자동 타입 보호
👉 교안에서는 useState를 제네릭의 가장 직관적인 예시로 설명합니다.
2.4 never 타입의 실제 의미
never는 “절대 발생할 수 없는 상태”를 의미합니다.
type Props = Record<string, never>
이 타입은 다음을 의미합니다.
“이 컴포넌트는 어떤 props도 받지 않는다”
즉, never는 결과값이 없는 것이 아니라, 존재 자체가 불가능한 상태를 표현하기 위한 타입입니다.
3. 가장 헷갈리는 개념: 인덱스 시그니처와 덕 타이핑
3.1 인덱스 시그니처의 위험성
type Hello = {
[key: string]: string
}
이 방식은 편리하지만, 다음과 같은 문제가 있습니다.
hello['없는키'] // undefined
타입스크립트가 존재하지 않는 키 접근을 막아주지 못합니다. 그래서 교안에서는 다음을 권장합니다.
Record<'hello' | 'hi', string>
또는
key in 'hello' | 'hi' 형태로 키 범위를 제한
3.2 덕 타이핑과 Object.keys가 string[]인 이유
타입스크립트는 덕 타이핑(구조적 타이핑)을 사용합니다.
“모양이 같으면 같은 타입이다”
이 철학 때문에 자바스크립트 객체는 항상 ‘열려 있는 구조’로 취급됩니다. 그래서 Object.keys(obj)의 반환 타입은 항상 string[]입니다.
Object.keys(hello).map(key => {
hello[key] // ❌ 에러
})
해결 방법은 다음 중 하나입니다.
해결책 ①: key as keyof Hello (내가 책임질게)
Object.keys(hello).map(key => {
const k = key as keyof Hello
hello[k] // ✅
})
해결책 ②: 헬퍼 함수 (한 번만 책임지고, 계속 안전)
function keysOf<T extends object>(obj: T): Array<keyof T> {
return Object.keys(obj) as Array<keyof T>
}
keysOf(hello).map(key => {
hello[key] // ✅
})
👉 이 설계는 타입 안정성보다 JS의 유연성을 우선한 결과입니다.
4. 기존 자바스크립트 프로젝트를 타입스크립트로 전환하기
4.1 tsconfig.json부터 준비하기
{ "compilerOptions":
{ "allowJs": true,
"target": "es5",
"outDir": "./dist" },
"include": ["./src/**/*"]
}
allowJs: JS + TS 공존target: 결과물 JS 버전outDir: 트랜스파일 결과 위치
4.2 JSDoc + @ts-check로 점진적 전환
// @ts-check
/**
* @param {number} a
* @param {number} b
* @returns {number}
*/
function sum(a, b) {
return a + b
}
이 코드는 순수 자바스크립트 파일에서 JSDoc과 @ts-check를 이용해 타입스크립트 컴파일러로 타입 검사를 수행하도록 만든, 점진적 타입 도입을 위한 코드다.
👉 파일 확장자를 바꾸지 않고도 타입 검증 가능 👉 대규모 프로젝트에서 매우 현실적인 전략
4.3 @types 패키지의 역할
lodash 같은 JS 라이브러리는 타입 정보가 없을 수 있습니다.
npm install -D @types/lodash
이렇게 하면 타입스크립트가 라이브러리 사용법을 이해할 수 있습니다. (DefinitelyTyped 커뮤니티에서 관리)