들어가며
TS를 사용하다보면 언제 type alias와 interface를 구분해서 사용할지 모호한 경우가 많습니다. interface방식이 확장성이 좋다는 말이 많은데, 사실 유니언 타입을 사용하면 type alias 방식도 확장이 가능합니다.
// interface
interface Point {
x: number;
y: number;
}
interface SetPoint {
(x: number, y: number): void;
}
// type alias
type Point = {
x: number;
y: number;
};
type SetPoint = (x: number, y: number) => void
이에 대해서 우아한 타입스크립트와 stack overflow의 내용을 정리하여 언제 type aliases(이하 타입별칭) 방식을 쓰고 언제 interface(인터페이스)를 사용할 지 구분하려고 합니다.
타입 별칭만 쓸 수 있는 경우
// primitive
type Name = string;
// object (인터페이스도 사용가능)
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };
// union
type PartialPoint = PartialPointX | PartialPointY;
// tuple
type Data = [number, string];
타입 별칭은 인터페이스와 달리 원시값, 유니온 , 튜플 타입에서 사용이 가능합니다.
모두 사용 가능한 경우
이외에는 문법적 차이가 존재하지만 두 가지 방법 모두 구현이 가능합니다.
객체 선언
type BirdType = {
wings: 2;
};
interface BirdInterface {
wings: 2;
}
const bird1: BirdType = { wings: 2 };
const bird2: BirdInterface = { wings: 2 };
// Because TypeScript is a structural type system,
// it's possible to intermix their use too.
const bird3: BirdInterface = bird1;
두 가지 방법모두 사용할 수 있으면 타입스크립트는 구조적 타입시스템을 가지기 때문에 혼용해서 사용가능합니다.
확장 ( 출처 )
Interface extends interface
interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }
Type alias extends type alias
type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };
Interface extends type alias
type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }
Type alias extends interface
interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };
implement
interface Point {
x: number;
y: number;
}
class SomePoint implements Point {
x = 1;
y = 2;
}
type Point2 = {
x: number;
y: number;
};
class SomePoint2 implements Point2 {
x = 1;
y = 2;
}
type PartialPoint = { x: number; } | { y: number; };
// FIXME: can not implement a union type
class SomePartialPoint implements PartialPoint {
x = 1;
y = 2;
}
interface의 타입별칭과의 차이점
인터페이스의 타입 별칭과의 차이점은 interface는 열려 있고 type 별칭은 닫혀 있다는 점입니다.
이는 interface를 두 번째로 선언함으로써 확장할 수 있다는 뜻입니다. 이를 선언 병합(Declaration merging)이라고도 합니다.
interface Kitten {
purrs: boolean;
}
interface Kitten {
colour: string;
}
// In the other case a type cannot be changed outside of
// its declaration.
type Puppy = {
color: string;
};
type Puppy = {
toys: number;
};
이러한 점이 interface가 더욱 확장성이 높다고 하는 근거입니다.
그럼 어떤 것을 사용해야할까?
우아한 타입스크립트 with React 에서 배달의 민족팀이 사용하는 방법과 위의 정보를 요약하면 아래와 같습니다.
원시타입, 유니온, 튜플 : 이 3가지의 경우에는 타입 별칭밖에 사용할 수 없습니다.
유틸리티 타입 : 타입 별칭 밖에 사용할 수 없습니다. ex)type PartialUser = Partial<User>
컴퍼넌트의 props의 경우 : 확장성이 높은 interface 사용 ex) Dialog컴퍼넌트를 만들때 다른 컴퍼넌트와 공유되는 interface
객체 지향적으로 코드 작성 시 : 특히 상속의 관련된 경우 interface
계산되는 타입(Computed value) : 타입 별칭 사용
const colors = {
primary: '#00f',
secondary: '#0f0',
danger: '#f00',
} as const;
// computed value로부터 타입 만들기
type ColorKey = keyof typeof colors;
이외에는 팀적 컨벤션에 따라 달라졌습니다.
type은 추론이 더 잘된다는 장점이 있어서 type 위주로 쓰는 팀도 있고 , 정적이거나 작은 범위는 type 그 외에는 interface를 사용하는 팀도 있습니다.
저는 후자의 방식을 선호해서 대부분 interface로 사용하고 있습니다.
출처 및 참고문헌
https://stackoverflow.com/questions/37233735/interfaces-vs-types-in-typescript/52682220#52682220
TS Playground - An online editor for exploring TypeScript and JavaScript
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
www.typescriptlang.org
우아한 타입스크립트 with 리액트 (우아한형제들 웹프론트개발그룹 지음)
'프론트엔드' 카테고리의 다른 글
React 유저가 느낀 Vue (0) | 2025.01.13 |
---|---|
전역상태관리 라이브러리 Jotai의 WeakMap을 활용한 메모리 최적화 (0) | 2024.09.19 |
Three.js 튜토리얼 - 기본 구조와 사용 방법 (0) | 2024.04.10 |
(React)컴파운드 패턴으로 드롭다운 컴퍼넌트 만들기-1 구현하기 (0) | 2024.03.28 |
React에 StoryBook 도입하기(tailwind) (0) | 2024.02.23 |