-
아이템 13 - 타입과 인터페이스의 차이점 알기타입스크립트 2023. 3. 7. 09:28
타입스크립트에서 명명된 타입을 정의하는 방법은 두 가지가 있다.
타입을 사용하는 방법
type TState = { name: string; capital: string; }
인터페이스를 사용하는 방법
interface IState { name: string; capital: string; }
대부분의 경우에는 타입을 사용해도 되고 인터페이스를 사용해도 되는데, 타입과 인터페이스 사이에 존재하는 차이를 분명하게 인식함으로써 같은 상황에서 동일한 방법으로 명명된 타입을 정의해 코드의 일관성을 유지할 수 있도록 해야한다.
인터페이스 선언과 타입 선언의 비슷한 점
잉여 속성 체크할 수 있다.
// type 키워드를 사용할 경우 type TState = { name: string; capital: string; } const wyoming: TState = { name: 'Wyoming', capital: 'Cheyenne', population: 500_000 // ~~~~~~~~~~~~~~~~~~ Type ... is not assignable to type 'TState' // Object literal may only specify known properties, and // 'population' does not exist in type 'TState' }; // 인터페이스를 사용할 경우 interface IState { name: string; capital: string; } const wyoming: IState = { name: 'Wyoming', capital: 'Cheyenne', population: 500_000 // ~~~~~~~~~~~~~~~~~~ Type ... is not assignable to type 'IState' // Object literal may only specify known properties, and // 'population' does not exist in type 'IState' };
인덱스 시그니처를 사용할 수 있다.
type TDict = { [key: string]: string }; interface IDict { [key: string]: string; }
함수 시그니처를 만들 수 있다.
// type 키워드를 사용할 경우 type TFn = (x: number) => string; const toStrT: TFn = (x) => '' + x; // OK // 인터페이스를 사용할 경우 interface IFn { (x: number): string; } const toStrI: IFn = (x) => '' + x; // OK
제네릭을 사용할 수 있다.
type TPair<T> = { first: T; second: T; } interface IPair<T> { first: T; second: T; }
타입을 확장할 수 있다. (단, 인터페이스는 유니온 타입 같은 복잡한 타입은 확장 불가능하다.)
// type 키워드를 사용할 경우 type TState = { name: string; capital: string; } type TStateWithPop = IState & { population: number; }; // 인터페이스를 사용할 경우 interface IState { name: string; capital: string; } interface IStateWithPop extends IState { population: number; }
클래스를 구현(implements)할 수 있다.
// type 키워드를 사용할 경우 type TState = { name: string; capital: string; } class StateT implements TState { name: string = ''; capital: string = ''; } // 인터페이스를 사용할 경우 interface IState { name: string; capital: string; } class StateI implements IState { name: string = ''; capita: string = ''; }
인터페이스 선언과 타입 선언의 차이점
유니온 타입은 존재하지만 유니온 인터페이스는 존재하지 않는다.
type AorB = 'a' | 'b';
인터페이스는 타입을 확장할 수 있지만, 인터페이스의 프로퍼티의 타입 중 유니온 타입은 확장할 수 없다.
type Input = { /* ... */ }; type Output = { /* ... */ }; type VariableMap = Input | Output; interface VariableMap { [name: string]: Input | Output; } // 만약 Input 혹은 Output 타입에 name이라는 프로퍼티가 추가된 타입을 만들고 싶다면 type 키워드로 다음과 같이 만들 수 있지만 인터페이스로는 만들 수 없다. type NamedVariable = (Input | Output) & { name: string };
튜플과 같은 배열 타입을 타입과 인터페이스로 선언할 수 있지만, 인터페이스로 선언한 튜플 타입은 배열에서 사용할 수 있는
concat
같은 메서드를 사용할 수 없다. 따라서 튜플은type
키워드로 구현하는 것이 좋다.// type 키워드를 사용할 경우 type Pair = [number, number]; const t: Pair = [10, 20]; // OK t.concat(); // OK // 인터페이스를 사용할 경우 interface Pair { 0: number; 1: number; length: 2; } const t: Pair = [10, 20]; // OK t.concat(); // ~~~~~~~~~~~~~~~~~~ Property 'concat' does not exist on type 'Pair'
인터페이스에서만 타입을 보강할 수 있다.
// 이 예제처럼 속성을 확장하는 것을 선언 병합(declaration merging)이라고 한다. interface IState { name: string; capital: string; } interface IState { population: number; } const wyoming: IState = { name: 'Wyoming', capital: 'Cheyenne', population: 500_000 }; // OK
타입 선언 vs 인터페이스 선언
- 복잡한 타입을 정의할 때는 인터페이스보다
type
키워드를 사용하는 것이 좋다. - 타입 선언과 인터페이스 두 가지 방법으로 모두 표현할 수 있고, 기존 프로젝트 스타일이 확립된 경우라면 일관성을 유지하는 것이 좋고, 프로젝트 스타일이 확립되지 않은 경우에는 보강의 가능성이 있는지 고려하여 타입을 선언하는 것이 좋다.
'타입스크립트' 카테고리의 다른 글
아이템 21 - 타입 넓히기 (0) 2023.03.14 아이템 20- 다른 타입에는 다른 변수 사용하기 (0) 2023.03.14 아이템 19 - 추론 가능한 타입을 사용해 장황한 코드 방지하기 (0) 2023.03.14 아이템 12 - 함수 표현식에 타입 적용하기 (0) 2023.03.07 아이템 11 - 잉여 속성 체크의 한계 인지하기 (0) 2023.03.07