I turn coffee into code ☕ → 💻 자세히보기

개발/TypeScript

[TypeScript] interface와 type의 차이점

xuwon 2025. 8. 9. 13:44
interface

객체(클래스, 구조체 등) 형태 정의
- 주로 객체 구조 정의
- extends로 확장
- 선언 병합 가능! (같은 이름 interface 여러 번 선언 시 자동 병합)

interface Person {
  name: string;
}

interface Person {
  age: number;
}

// 병합된 최종 Person 타입
const p: Person = {
  name: "Alice",
  age: 25
};

type

더 넓은 범위의 타입 별칭(Alias) 정의
- 객체 구조 + 기본 타입 + 유니온 + 튜플 + 제네릭 등 가능
- &(Intersection)으로 확장
- 선언 병합 불가능


1. 객체 형태 정의

interface User {
  name: string;
  age: number;
}

type UserType = {
  name: string;
  age: number;
};

두 방법 모두 동일하게 작동.

 
2. 확장 방법

// Interface 확장
interface User {
  name: string;
}
interface Admin extends User {
  role: string;
}

// Type 확장
type UserType = {
  name: string;
};
type AdminType = UserType & { role: string };

 
3. 선언 병합

interface User {
  name: string;
}
interface User {
  age: number;
}
// 병합 결과: { name: string; age: number }

type UserType = { name: string };
// ❌ 아래는 에러 (type은 병합 불가)
// type UserType = { age: number };

 
4. 유니온, 튜플 등

// ✅ type 가능
type Status = "loading" | "success" | "error";
type Point = [number, number];

// ❌ interface 불가능 (유니온, 튜플 직접 표현 안 됨)

 


interface
- 객체, 클래스의 구조 정의에 최적
- 확장과 선언 병합 기능 덕에 라이브러리 타입 보강에 좋음
- 주로 "이 타입은 이렇게 생겼다"고 말할 때

type
- 유니온, 튜플, 기본 타입 별칭까지 가능 → 더 범용적
- 선언 병합은 안되지만 표현력이 더 강함
- 주로 "이 타입은 이런 범위를 가진다"라고 할 때

아직도 좀 헷갈리고 언제 뭘 써야하는지는 계속 헷갈릴 거 같다..;;
팀 컨벤션에 따라 둘 중 하나로 통일하기도 한다고 한다.
 
API 응답 타입 구조를 만들 때는 inferface랑 type, 제네릭을 섞어서 쓴다고 한다.
 


제네릭이 뭐더라...ㅎㅎ

제네릭

타입을 나중에 결정하는 템플릿!

type ApiResponse = {
  data: string; // 무조건 string
  isLoading: boolean;
};

제네릭을 사용하지 않았을 경우는 타입을 정의하면 속성 타입이 고정됨!
 

type ApiResponse<T> = {
  data: T;
  isLoading: boolean;
};

제네릭을 사용하면 타입을 변수처럼 받아서 data의 타입을 고정시키지 않고 사용 가능
 

// 문자열을 응답으로 하는 API
const storyResponse: ApiResponse<string> = {
  data: "정릉에서 찍은 사진이에요",
  isLoading: false,
};

// 배열을 응답으로 하는 API
const storyListResponse: ApiResponse<string[]> = {
  data: ["사진1", "사진2"],
  isLoading: false,
};

// 객체를 응답으로 하는 API
type Story = { id: string; content: string };

const storyObjResponse: ApiResponse<Story> = {
  data: { id: "123", content: "오늘은 맑음" },
  isLoading: true,
};

이렇게 사용이 가능하다.


 
즉,
API 응답 “껍데기” (즉, data, isLoading, error 같은 공통 구조)는
type + 제네릭으로 만들어서 재사용성과 유연성을 극대화
내부 데이터 구조 (예: Story, EmotionTag 등 실제 비즈니스 도메인 타입)는
interface로 정의해서 확장이나 선언 병합 같은 이점 활용

// 껍데기
type ApiResponse<T> = {
  data: T;
  isLoading: boolean;
  error?: string;
}

// 도메인 데이터
interface Story {
  id: string;
  content: string;
  emotions: string[];
  createdAt: string;
}

// ApiResponse에 Story 끼워넣기
type StoryResponse = ApiResponse<Story>;

이렇게 예제로 보니 좀 이해가 되는 거 같다.
이번 프로젝트 때 써봐야겠다!