타입스크립트의 타입과 인터페이스의 차이점을 설명해주세요.
타입과 인터페이스의 차이점은
const type name = {}
interface name {}
방식이라는 것으로만 생각난다.
이를 통해 생각나는건 변수로서 지정되느냐 아니면 선언되느냐의 차이 같긴 한데. .
사실 인터페이스도 extend 가 가능하여 어떤 차이점이 있는지는 명확히 모르겠다
interface 는 객체의 형태를 확장하는 데 용이한 반면,
type 은 튜플, 인터섹션, 유니온 등을 이용하여 더 복잡한 타입 정의 및 조합을 표현하는데 용의하다.
interface 는 선업 병합을 지원하여 여러번 선언이 가능하다.
객체타입을 확장할 때 유리하며 동일한 이름을 가진 interface 를 여러 번 선어하면 이 속성들이 자동으로 합쳐진다
interface Person {
age: number;
name: string;
isBirthday: boolean;
}
interface Person {
address: string;
}
const person1: Person = {
age: 1,
name: "abcd",
isBirthday: false,
address: "1010",
};
Person interface 를 여러 번 선언 가능하며, 결과적으로 하나의 interface 로 병합된다.
반면, type 으로 선언 한 경우에는 동일한 이름을 중복 선언하면 에러가 발생한다. 대신 튜플과 같은 복잡한 타입 표현이 가능하며 복잡한 타입 조합을 위해 인터섹션(&)과 유니온(|)연산자를 지원한다.
type BasicInfo = {
name: string;
age: number;
};
type ContactInfo = {
email: string;
phone: string;
};
// 인터섹션 타입 (&)을 사용해 두 타입을 결합하여 하나의 타입으로 생성
type PersonInfo = BasicInfo & ContactInfo;
const person2: PersonInfo = {
name: "John",
age: 30,
email: "john@example.com",
phone: "123-456-7890",
};
정리하자면, interface 는 선언 병합을 통해 여러 번 선언이 가능하며 객체 타입을 확장하는 데 유리하며, type 은 튜플 등 복잡한 타입을 사용하고 유연한 연산자를 통해 복잡한 타입 조합을 표현하는 데 적합하다.
'interface' 에만 가능한 선언 병합
// ✅ interface - 자동 병합
interface User {
name: string;
}
interface User {
age: number; // 병합됨
}
// ❌ type - 중복 선언 불가
type User = {
name: string;
}
type User = { // Error: Duplicate identifier
age: number;
}
'type' 타입 표현의 유연성
// 원시 타입 별칭 - type만 가능
type ID = string | number;
type Status = "pending" | "completed" | "failed";
// 튜플 타입
type Coordinate = [number, number];
type RGB = [red: number, green: number, blue: number]; // 레이블된 튜플
// 조건부 타입
type IsString<T> = T extends string ? true : false;
// 매핑된 타입과 템플릿 리터럴
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};
'interface' 의 확장 방식의 차이
// Interface - extends 키워드
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// Type - 인터섹션(&) 사용
type Animal = {
name: string;
}
type Dog = Animal & {
breed: string;
}
성능적 차이
interface 는 캐싱이 효율적 (내부적으로 이름 참조)
Type 은 매번 평가되어야 한다 (유니온 / 인터섹션)
팀에서는
1. 일관성 이 가장 중요하다.
2. 선언병합이 필요한 경우 Interface
// 외부 라이브러리 타입 확장
declare module "express" {
interface Request {
user?: User;
}
}
// 조건부 타입 체이닝
type AsyncReturnType<T> =
T extends (...args: any[]) => Promise<infer R> ? R :
T extends (...args: any[]) => infer R ? R :
never;