Home
PostsAbout
react
typescript

타입과 인터페이스의 차이점 알기

Type Alias와 Interface 둘 중 무엇을 선택해야 할까?

2024-01-07

💡 대부분의 경우에는 타입을 사용해도 되고 인터페이스를 사용해도 됩니다. 다만 하나의 프로젝트에서 같은 상황에서는 동일한 방법으로 명명된 타입을 정의해 일관성을 유지해야 합니다.

현대 프론트엔드 개발에서 순수 자바스크립트만으로 서비스를 개발하는 경우는 자주 못 본 것 같습니다. 회사 프로젝트도 그렇고 사이드 프로젝트도 너무나 당연하게 타입스크립트로 프로젝트를 시작합니다. 하지만 그 때마다 고민했던 문제가 있습니다. 바로 타입을 정의하는 방법입니다.

팀원들에게 어떤 방법으로 타입을 정의해야하는지에 대해 의견을 물으면, 확실한 근거보다는 “나는 Type Alias를 선호해!” 또는 “나는 Interface가 좋더라”라고 하는 경우가 많았습니다. 저 또한 저 둘의 사용에 대한 확실한 근거를 대지 못했고 그저 다수의 팀원들이 선호하는 방식으로 타입을 정의하였습니다.

따라서 이번 기회에 Type AliasInterface의 공통점과 차이점을 확실히 알고 그 내용을 정리하도록 하겠습니다.

공통점

정말 대부분의 경우에는 Type Alias에서 사용할 수 있는 기능들을 Interface에서도 사용할 수 있습니다. 다음은 몇 가지 둘의 공통점입니다.

타입 이름 짓기

Type AliasInterface둘 다 타입의 이름을 짓는 방법은 별 다를게 없습니다. 다음과 같이 타입을 정의하고 지정합니다.

interface Dog {
	name: string;
	breed: string;
	age: number;
} 

const 까미: Dog = {
	name: '까미',
	breed: '푸들',
	age: 11,
};

type Dog = {
	name: string;
	breed: string;
	age: number;
}

const 까미: Dog = {
	name: '까미',
	breed: '푸들',
	age: 11,
};

예시를 들어 타입을 지정해보고 나니 사실 완전 똑같아 보입니다.

인덱스 시그니처

Type AliasInterface둘 다 인덱스 시그니처를 사용할 수 있습니다.

interface DogDictionary {
	[key: string]: string;
}

type DogDictionary = {
	[key: string]: string;
}

함수 타입 정의

Type AliasInterface 둘 다 함수 타입을 정의할 수 있습니다.

interface SomeFunction {
	(dog: string): string;
}

type SomeFunction = {
	(dog: string): string;
}

이외에도 제너릭 사용, 인터페이스의 타입 확장, 타입의 인터페이스 확장 등의 공통점이 있습니다.

차이점

유니온

유니온 타입은 있지만 유니온 인터페이스라는 개념은 없습니다. Interface는 타입을 확장할 수는 있지만 유니온을 확장할 수는 없습니다.

type Dog = '푸들' | '포메'; // O

interface Dog { '푸들' | '포메' }; // X

따라서 인터페이스를 사용하고 싶은데 유니온 타입을 확장해야하는 경우는 다음과 같이 작성할 수 있습니다.

type Input = { /* ... */ };
type Output = { /* ... */ };
interface VariableMap {
	[name: string]: Input | Output;
}

// 예시 출처: Effective Tyepscript 아이템 13

유니온 타입에 어떠한 타입을 붙이고 싶은 경우는 Interface로는 표현할 수 없습니다.

type NamedVariable = (Input | Output) & { name: string };

// 예시 출처: Effective Tyepscript 아이템 13

Type Alias 은 일반적으로 Interface보다 쓰임새가 많습니다. 유니온 타입을 표현할 수 있으며, 매핑된 타입 또는 조건부 타입 같은 고급 기능에도 활용할 수 있습니다.

declaration merging

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

interface Dog {
	breed: string;
}

const 까미: Dog = {
	name: '까미',
	age: 11,
	breed: '푸들'
}; // 정상

인터페이스는 위 예제처럼 속성을 확장할 수 있고, 이것을 선언 병합(declaration merging)이라고 합니다. 선언 병합은 주로 타입 선언 파일에서 사용되며 Type Alias에서는 사용할 수 없기 때문에 선언 병합을 사용하기 위해서는 반드시 Interface를 사용해야 합니다. 선언 병합을 통해 사용자는 타입 선언에 있을 수 있는 빈틈을 채울 수 있습니다.

객체 지향의 사실과 오해

위에까지는 구글에 검색하였을 때에도 많이 나오는 일반적인 사실들이고, 사실 둘의 공통점을 살펴보았을 때 그 어느 것을 선택하더라도 크게 다른 점은 없어보입니다. 타입스크립트 팀과 많은 아티클에서도 팀에서 유지하고 있는 타입 정의 방식이 있다면 그것을 따르고 일관성을 유지하는 것이 더 중요하다고 말합니다. 그래서 저는 좀 더 현실적으로 현업에 있는 다른 개발자들의 의견을 들어보고자 했습니다.

회사에서 풀스택으로 개발하시는 동료 분께 인터페이스와 타입에 대해 여쭤본 적이 있습니다. 그때 그 분은 객체 지향의 사실과 오해에 나오는 내용을 인용하여 그 분의 의견을 설명해주셨습니다.

일반적으로 인터페이스란 어떤 두 사물이 마주치는 경계 지점에서 서로 상호작용할 수 있게 이어주는 방법이나 장치를 의미한다.

그렇기 때문에 객체의 행위를 외부 모듈에 드러내는 용도로는 인터페이스가 의미적으로 더 적합해보인다는 말씀이셨습니다.

인터페이스의 의미를 그렇게 살펴보니 외부 모듈에 Props로 전달하는 용도로는 인터페이스가 적합하지 않을까라는 생각이 들었습니다.

하지만 이렇게도 생각할 수 있을 것 같습니다. “인터페이스의 그런 의미라면 정말로 외부에 공개하는, 즉 프로젝트를 함께 진행하는 팀원이 아닌 외부인에게 공개하는 모듈의 경우에(ex.공공 API) 인터페이스를 사용하는 것이 의미적으로 적합하지 않을까? 그렇게 설계한다면 타입스크립트에서 의도한대로 선언 병합을 사용할 수도 있고…”

Type Alias가 사용하기 더 편리하다?

모 IT 기업의 프론트엔드 리드급으로 계시는 현재 스터디 멘토님에게도 이 글의 주제에 대해 여쭤본 경험이 있습니다. 이 분의 대답은 꽤 유쾌하게 들렸습니다.

Type Alias는 type이라고 네 글자의 타이핑만 하면 되지만, Interface는 interface라고 아홉 글자나 타이핑해야한다. Type Alias가 타이핑하기에도 편하고 Type AliasInterface로 표현할 수 있는 대부분의 표현을 할 수 있다. 그래서 굳이 Interface를 사용해야 할 필요를 못 느꼈고, 우리 팀은 일관되게 Type Alias를 사용하고 있다.”

이렇게 보면 개발자 경험 측면에서 Type Alias를 사용하는 것이 좀 더 나아보입니다. 말씀하신 것처럼 타이핑하는 양도 적고, InterfaceType Alias 사이에 유의미한 차이가 없다면, 그 둘을 구분해서 사용하는데 노력을 쏟지 않고 일관되게 쓴다는 점이 그렇게 느껴졌습니다.

“객체 지향으로 개발하시는 분들이 InterfaceType Alias의 의미로 접근하시는데, 객체 지향으로 개발하고 있지 않는다면야…” 라는 말씀도 하셨는데, 제가 프론트엔드 개발을 할때 객체 지향 프로그래밍을 하지 않기 때문에 공감이 가는 부분이었습니다.

결론

결론이 애매하게 횡설수설하게 나왔는데 어쨌든 이에 대한 저의 생각을 정리해보자면 다음과 같습니다.

  • 외부에 공개하는 API의 경우에는 Interface로 타입을 설계하여 선언 병합을 사용할 수 있도록 하자.
  • 프로젝트 안에서 사용하고 있는 React Component나 State의 타입의 경우에는 Type Alias를 사용하자.
    • 프로젝트 내부적으로 사용되는 타입에 선언 병합이 발생하는 것은 잘못된 설계다. (Effective TypeScript)
  • 어쨌든 팀이 일관성 있게 무언가를 선택하고 있다면 그것을 따르자.

참고