우당탕탕

TypeScript 처음 도입하면서 헷갈렸던 부분들 정리!! 본문

언어/JavaScript

TypeScript 처음 도입하면서 헷갈렸던 부분들 정리!!

모찌모찝 2026. 5. 11. 09:50

 

저도 처음 TypeScript를 프로젝트에 도입할 때 생각보다 헷갈리는 부분이 많았거든요. 타입을 하나하나 맞춰야 하는 게 익숙하지 않다 보니 삽질도 많이 했고, 어떤 부분에서 타입을 강제해야 하는지 감이 안 오는 경우도 있었어요.

이 글에서는 제가 TypeScript를 처음 도입하면서 겪었던 대표적인 혼란 포인트들을 직접 해결한 방법과 함께 차근차근 정리해 볼게요. 타입 선언부터 인터페이스, 유니언 타입, 그리고 타입 추론과 관련된 부분까지 실제 코드를 곁들여 설명합니다.

TypeScript 처음 도입하면서 헷갈렸던 것들 정리 관련 이미지

TypeScript 처음 도입하면서 헷갈렸던 것들 정리 관련 정보

 

저는 이렇게 개발 환경을 세팅했어요

저는 TypeScript 5.0 버전을 사용했고, 프론트엔드 프레임워크는 주로 React 18였어요. 타입스크립트 설정은 기본 tsconfig.json에 strict 모드를 켠 상태였고요. yarn이나 npm으로 타입 정의 패키지를 꼭 설치해 주는 것도 잊지 않았습니다.

처음엔 변수나 함수 매개변수 타입 지정이 제일 헷갈렸어요

사실 이 부분이 TypeScript 초심자가 가장 많이 막히는 지점인 것 같은데요, \"any\" 타입을 쓰면 편하지만, 타입 검사의 의미가 크게 사라져서 잘 안 쓰는 게 맞아요. 그래서 구체적인 타입을 지정하는 게 중요한데, 처음에는 아래처럼 많이 헤맸어요.

function greet(name) {
    return `Hello, ${name.toUpperCase()}`;
 }
 // 이렇게만 쓰면 name이 어떤 타입인지 몰라 에러 발생

이걸 해결하려면 매개변수에 타입을 명시해야 하는데요, 이렇게 합니다.

function greet(name: string): string {
    return `Hello, ${name.toUpperCase()}`;
}

이렇게 하면 name은 반드시 문자열로 들어와야 하고, 함수도 문자열을 반환한다고 강제할 수 있죠. 저는 이 부분부터 타입스크립트가 얼마나 버그를 미리 잡아주는지 체감하기 시작했어요.

인터페이스와 타입 별칭, 여기는 정말 처음에 헷갈렸던 포인트

그런데 여기서 많이들 헷갈려하시는 게 interfacetype 두 가지를 언제 써야 하는지인데요, 저도 처음에는 거의 구분 못 했었어요.

기본적으로는 둘 다 객체의 형태를 정의할 수 있는 타입이지만, interface가 좀 더 확장성이 좋고, type은 유니언 타입 등 좀 더 복잡한 타입 표현에 유리해요. 예를 들어 이런 차이가 있습니다:

// interface 예시
interface User {
    id: number;
    name: string;
}

// type alias 예시
// 유니언 타입도 가능
type Status = \"pending\" | \"success\" | \"error\";

저는 주로 객체 형태를 표현할 땐 interface를, 문자열이나 숫자 값의 집합처럼 특정 값만 허용할 땐 type을 쓰는 편이에요.

유니언 타입과 타입 가드, 이 부분에서 한참 삽질했죠

TypeScript에서 여러 타입 중 하나를 허용하는 유니언 타입을 쓸 때, 타입스크립트가 자동으로 정확한 타입을 추론해 주지 않아서 타입 에러가 나는 경우가 많았어요.

이럴 때는 직접 “타입 가드”를 써서 타입스크립트에게 \"지금 이 변수는 이 타입 맞아요\"라고 알려줘야 하는데, 제가 한 예시가 아래 코드예요.

type Fish = { swim: () => void };
type Bird = { fly: () => void };

type Pet = Fish | Bird;

function move(pet: Pet) {
    if (\"swim\" in pet) {
    pet.swim();  // 타입스크립트가 swim이 Fish에만 있다고 인식
} else {
    pet.fly();
}
}

이 if문 덕분에 막혔던 코드가 한방에 풀렸죠. 처음에는 \"in\" 연산자 대신 그냥 pet.swim()을 호출해서 에러가 엄청 났거든요.

타입 추론과 any, unknown, never 차이도 꼭 알아야 했어요

특히 any를 쓰면 타입 검사가 무력화돼서 문제지만, unknown은 좀 더 안전한 타입인데도 처음엔 이걸 헷갈렸어요.

예를 들어 이렇게 구분합니다:

  • any: 모든 타입을 허용하고 검사하지 않아서 최대한 피하는 게 좋아요.
  • unknown: 어떤 값이 올지 모를 때 쓸 수 있으나, 실제 사용 전에 타입 체크를 해야 해서 안전해요.
  • never: 절대 발생하지 않는 타입으로, 에러 핸들링이나 함수가 반환하지 않을 때 씁니다.

이걸 구분하기 전까지는 코드 작성할 때 자꾸 any만 써서 나중에 유지보수할 때 고생했는데, 정확히 알게 되고 나서는 코드 안정성이 훨씬 올라가더라고요.

TypeScript 처음 도입하면서 헷갈렸던 것들 정리 관련 이미지

TypeScript 처음 도입하면서 헷갈렸던 것들 정리 관련 정보

여기서 삽질했던 부분과 해결한 방법들

가장 많이 막혔던 건 타입 선언이 너무 엄격해서 발생하는 에러였는데요, 특히 \"Property 'x' does not exist on type 'Y'\" 이런 에러 메시지가 뜰 때마다 왜 그런지 한참 헤맸습니다.

// 문제 상황 예시\nconst person = { name: \"John\" };

console.log(person.age);  // Property 'age' does not exist on type '{ name: string; }'

이럴 땐 애초에 타입 정의에 해당 프로퍼티가 없다고 타입스크립트가 경고해 주는 거라서, 타입을 다시 정의하거나, 옵셔널 체이닝을 쓰는 게 해결 방법이에요.

가령 이렇게 고쳤습니다:

interface Person {
    name: string;
    age?: number;  // 물음표로 옵셔널 지정
    
    
    const person: Person = { name: \"John\" };
    console.log(person.age ?? \"나이 정보 없음\");

저는 이 패턴을 알게 되고 나서 타입 에러로부터 훨씬 자유로워졌어요.

이건 알면 좋아요, 타입스크립트 최적 활용 팁

직접 경험해보니, 타입스크립트의 장점을 최대한 살리려면 가능한 한 타입을 엄격히 관리하는 게 중요하더라고요. 그리고 아래 두 가지를 꼭 기억하세요.

  • 자동 타입 추론을 믿되, 애매한 부분은 명시적으로 타입을 지정하기
  • 컴포넌트나 함수 인터페이스는 깨끗하게 유지하고 재사용 가능한 타입 별칭 만들기

그리고 React를 쓴다면 React.FC 타입이나 hooks 타입 설정도 꼭 익혀두시면 훨씬 편리해요!

Comments