Interface와 Type Alias
일반적으로 object 타입에 대해 타입 선언을 할 때에는 둘에 별 차이가 없다.
선언 예시
interface Cat {
name: string;
age: number;
}
type Cat = {
name: string;
age: number;
}
// 사용은 둘 다 똑같다
const kitty: Cat = {
name: 'Kitty',
age: 5
}
다만 공식 문서의 type alias와 interface 항목을 보면 다음과 같이 정의되어 있다.
type alias
- A type alias is exactly that - a name for any type.
- 변수 옆에 콜론(:)으로 직접 타입을 지정하던 것을 여러번 재사용하고 별칭을 지어주기 위한 목적으로 만들어졌다.
interface
- An interface declaration is another way to name an object type
- object 타입을 정의하기 위한 방법이다.
type alias는 타입에 별칭을 붙여주는 것이다. 그렇기 때문에 type alias는 object 외의 원시 타입들도 선언이 가능하다.
// 원시 타입 지정 가능 (boolean, number, string 등)
type Name = string;
// 유니온 타입(or) 혹은 인터섹션 타입(and) 지정 가능
type BtnColor = 'red' | 'green';
Interface와 Type Alias 차이점
둘다 확장 가능, 하지만 Interface는 제약이 많다.
interface
- interface는 extends 키워드로 확장할 수 있다.
- 쉼표(,)로 다중 확장이 가능하다. type alias에서 &로 새로운 타입을 정의하는 것에 대응되는 개념이다. 하지만 약간의 제약이 있다.
-> 만약 extends 해서 만들어지는 interface에 슈퍼 타입과 같은 속성이 존재한다면, 그 속성은 슈퍼타입의 것보다 범위가 작거나 같아야 한다.
// Case 1
interface Foo {
a: string;
}
// 에러
interface Bar extends Foo {
a: boolean;
b: number[];
}
// Case 2
interface Foo {
a: string | boolean;
}
// OK
interface Bar extends Foo {
a: boolean;
b: number[];
}
다중상속 - Case 1에서 결과물은 Foo와 Bar의 교집합인 number[]일 줄 알았는데 에러가 발생한다. 다중상속은 같은 속성이 있다면 타입을 갖게 맞춰야 한다.
/* Case 1 */
interface Foo {
a: (string | number)[]
}
interface Bar {
a: number[]
}
// 에러
interface MultipleExtends extends Foo, Bar {}
/* Case 2 */
interface Foo {
a: number[]
}
interface Bar {
a: number[]
}
// OK
interface MultipleExtends extends Foo, Bar {}
type alias - intersection type
- type alias는 & 를 통해 확장할 수 있다.
- 그리고 같은 속성에 대해 서로 타입이 다른 경우, 인터섹션 한 결과는 둘을 And한 것과 같다.
- 하지만 string이면서 동시에 number인 타입이 존재 할 수 없듯이, never (불가능한 값)이 되버린다. 사실상 interface였다면 에러가 발생했을 텐데 인터섹션 타입을 정의할 당시에는 에러가 뜨지 않으므로 주의해야 한다.
클래스를 implements 할 시점에서야 never 타입이라고 에러가 뜬다.
interface Foo {
a: string
}
interface Bar {
a: number
}
type Intersection = Foo & Bar
// Intersection 결과
{
a: string & number
}
중복 선언 가능 여부
interface - 가능
- Interface를 여러 번 선언하면 마치 모두 합한 것처럼 동작한다. 프로퍼티는 중복으로 존재해도 되지만, 타입이 같아야 한다.
- 이를 선언 병합이라고 한다.
interface Dog {
name: string;
}
interface Dog {
name: string;
age: number;
}
// 최종적으로 이것처럼 동작한다.
interface Dog {
name: string;
age: number;
}
type alias - 불가
type Dog = {
name: string;
}
type Dog = {
name: string;
age: number;
}
// 에러 발생
따라서 추가로 interface를 선언해 타입을 확장할 일이 많은 경우(라이브러리, API)의 타입은 interface로 선언하는 것이 좋다. type alias를 이용한 &
나 |
연산이 꼭 필요할 때를 제외하고는 웬만하면 interface로 선언하자.
Interface와 Type Alias 공통점
둘 다 extends, implements 할 때 사용할 수 있다.
둘 다 interface를 extends 할 때, 혹은 class를 implements 할 때 사용할 수 있다.
다만 제한이 있는데 바로 '정적 타입일 것'
일반적인 object 타입이나 인터섹션 타입이면 문제가 없지만,
합 타입(유니온 타입)이면 에러가 발생한다.
(1) 일반적인 타입 정의인 경우
interface Animal {
name: string;
age: number;
legs: number;
}
type Animal = {
name: string;
age: number;
legs: number;
}
// interface로 정의한 것과 type으로 정의한 것 둘 중 무엇을 사용해도 상관 없다
class Cat implements Animal {
// ...
}
(2) 합 타입인 경우
type Animal = {
name: string;
age: number;
legs: number;
}
type Cat = {
tail: boolean;
}
type Kitty = Animal | Cat;
// Error 발생!
class MyKitty implements Kitty {
// ...
}
// Error 발생!
interface PinkKitty extends Kitty {}
(3) 곱 타입인 경우 - 정적 타입이라 모양을 알 수 있어 괜찮다.
type Kitty = Animal & Cat;
class MyKitty implements Kitty {
// ...
}
결론
- 인터섹션(And), 유니온(Or)로 새로운 타입을 만들 때, 튜플 타입을 정의할 때는 type alias를 쓰자. 단, And 되는 타입은 은 말이 되는지 주의깊게 보자.
- 확장성이 중요한 경우 interface로 타입 정의를 하자.
And, Or 타입 연산, tuple은 type alias로! 그 외의 경우는 interface로!
Reference
Type vs Interface, 언제 어떻게?
TypeScript에서 Type Alias와 Interface의 차이를 알아보기
medium.com
typescript에서의 다중 상속
우리 다중 상속하게 해주세요 🙏
velog.io
'Front-end > Typescript' 카테고리의 다른 글
[Typescript] React에서 type, interface는 어디에 정의하는게 좋을까? (0) | 2023.06.16 |
---|---|
[Typescript] 이미 존재하는 CRA에 Typescript 추가하기 (0) | 2023.06.02 |