Programming/TypeScript

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

앵도라지 2023. 4. 20. 11:05

이 글은 이펙티브 타입스크립트 '아이템 13 타입과 인터페이스의 차이점 알기'를 정리한 글입니다.

 

 

  • 타입스크립트에서 명명된 타입을 정의하는 방법은 두 가지가 있다.
    • 클래스를 사용할 수도 있지만, 클래스는 값으로도 쓰일 수 있는 자바스크립트 런타임 개념이다. (아이템 8에서 설명했음)
  • 대부분의 경우 타입을 사용해도 되고, 인터페이스를 사용해도 된다.
  • 타입과 인터페이스 사이에 존재하는 차이를 명확히 알고 같은 상황에서 동일한 방법으로 명명된 타입을 정의해 일관성을 유지해야 한다.

1. type 키워드 사용

type TState = {
	name : string;
	capital : string;
}

2. 인터페이스 사용

interface IState {
    name: string;
    capital: string;
}

3. 비슷한 점

  • 명명된 타입은 인터페이스로 정의하든 타입으로 정의하는 상태에는 차이가 없다.

1) 추가속성과 함께 할당한다면 동일한 오류가 발생한다.

const wyoming: TState = {
    name: 'wyoming',
    capital: 'Cheyenne',
    population: 500_000
};
//오류메세지 :  개체리터럴은 알려진 속성만 지정할 수 있으며 TState (또는 IState) 형식에 population이 없다.

2) 인덱스 시그니처를 사용할 수 있다.

//타입
type TDict = {[key: string]: string};

//인터페이스
interface IDict {
    [key: string]: string;
}

3) 함수타입의 정의가 가능하다.

//타입
type TFn = (x: number) => string;
const toStrT: TFn = x => '' + x;

//인터페이스
interface IFn{
    (x: number): string;
}
const toStrI: IFn = x => '' + x;

4) 제너릭이 가능하다

  • 제네릭이란 타입을 마치 함수의 파라미터처럼 사용하는 것을 의미함
type TPair<T> = {
    first: T;
    second: T;
}

interface IPair<T>{
    first: T;
    second: T;
}

5) 서로 확장이 가능하다.

  • type 을 extends 한 interface
  • interface 를 extends 한 type
interface IStateWithPop extends TState{
    population: number;
}

type TStateWithPop = IState & {population: number;};

4. 차이점

1) 유니온 인터페이스는 존재하지 않음 (유니온 타입은 있음)

type AorB = 'a' | 'b';
  • 인터페이스는 타입을 확장할 수 있지만, 유니온은 할 수 없다.
    • 그렇지만 유니온 타입을 확장하는 것이 필요할 때가 있다.

확장방법 1) Input | Output 타입을 갖는 객체를 표현하는 VariableMap 인터페이스

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

확장방법 2) 유니온타입에 name 속성을 붙인 타입 NamedVariable 타입

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

2) 인터페이스는 보강이 가능하다

  • 타입선언에는 사용자가 채워야하는 빈틈이 있을 수 있다. (선언병합 필요 - 6장)
  • 선언병합을 지원하기 위해 반드시 인터페이스를 사용해야 한다. (보강)
  • 병합은 선언처럼 일반적인 코드라서 언제든지 가능하다.
    • 프로퍼티가 추가되는 것을 원하지 않는다면 인터페이스 대신 타입을 사용할 수 있다.
//선언병합 예제
interface IState {
    name: string;
    capital: string;
}

interface IState {
    population: number;
}

const wyoming:IState = {
    name: 'Wyoming',
    capital: 'Cheyenne',
    population: 500_000 // 정상
};

5. 무엇을 사용해야 할까?

  • 타입과 인터페이스 중 어느 것을 사용해야 할까?
  • 복잡한 타입이라면 타입별칭을 사용하면 된다.
  • 타입과 인터페이스. 두 가지 방법으로 모두 표현할 수 있는 간단한 객체 타입이라면 일관성과 보강의 관점에서 고려해야 한다.
  • 이미 프로젝트가 진행중일 때 :
    • 일관되게 인터페이스를 사용하는 코드베이스라면, 인터페이스를 사용한다.
    • 반대의 경우에는 타입을 사용한다.
  • 아직 스타일이 확립되지 않은 프로젝트 일 때 :
    • 향후에 보강의 가능성이 있을지 생각해야 한다.
    • API에 타입 선언을 작성한다면 인터페이스를 사용해라
      • API가 변경될 때 사용자가 인터페이스를 통해 새로운 필드를 병할 할 수 있기 때문이다.
    • 프로젝트 내부적으로 사용되는 타입에 선언 병합이 발생하는 것은 잘못된 설계다.
      • 타입을 사용해라

요약

  • 타입과 인터페이스의 차이점과 비슷한 점을 이해해야 한다.
  • 한 타입을 type 과 interface 두 가지 문법을 사용해서 작성하는 방법을 터득해야 한다.
  • 프로젝트에서 어떤 문법을 사용할지 결정할 때 한 가지 일관된 스타일을 확립하고, 보강 기법이 필요한지 고려해야 한다.