타입과 인터페이스
타입과 인터페이스 되돌아보기
최근 타입과 인터페이스에 대한 확실한 이해 없이 그냥 평소 쓰던대로 쓰고 있는 자신을 발견했다.
타입과 인터페이스 차이를 물어봐도 당장 떠오르는게 인터페이스는 객체 타입을 정의할 때 쓰고, 타입은 인터페이스가 커버해주지 못하는 영역이나 유니온 타입 쓸 때 쓴다 정도밖에 답변이 안나왔다.
이상하다? 분명 내가 정리까지 해놓고 누가 물어보면 이렇게 답변해야지 하면서 외웠는데?
그렇다 이해하고 내걸로 만든게 아니라서 그렇다. 답변용으로 외웠다가 정작 답변이 필요할 때 답변하지 못하다니...
이건 적신호다.
명확히 구분하지 못하고, 쓰는 방식을 설명하지도 못하는 건 도저히 제대로 된 모습이라고는 못한다.
반성할 겸 재정리 하고, 코딩 컨벤션은 어떻게 사용하고 있는지 보려고 한다.
타입
- Type Aliases
- Type A = ... 형식으로 사용하는 타입 별칭 선언이다.
- 타입은 모든 유형의 이름이다. 타입 별칭을 사용하면 모든 타입에 대해 새로운 이름을 부여 할 수 있다.
- 중요한 건 별칭은 단지 별칭에 지나지 않는다는 것이다. 여러 버전을 만드는 게 아니다.
인터페이스
- 객체 타입을 만드는 또 다른 방법이다.
- 타입 별칭을 사용한 경우와 마찬가지로 타입이 없는 임의의 익명 객체를 사용하는 것처럼 동작한다.
- TypeScript는 오직 전달된 값의 구조에만 관심을 가지며, 예측된 프로퍼티를 가졌는지 여부만을 따진다.
타입 별칭과 인터페이스의 차이점
타입 별칭과 인터페이스는 매우 유사하며, 대부분의 경우 둘 중 하나를 자유롭게 선택할 수 있다.
가장 핵심적인 차이는, 타입은 새 프로퍼티를 추가하도록 개방되지 않는 반면 인터페이스는 항상 확장될 수 있다는 점이다.
- 타입 별칭은 선언 병합에 포함될 수 없지만 인터페이스는 포함 될 수 있다.
- 인터페이스는 객체의 형태를 선언하는 데에만 사용되며 기존 원시타입에 별칭을 부여하는 데에는 사용할 수 없다.
확장
//인터페이스 확장
interface Animal {
name: string
}
//extends를 통해 확장한다
interface Bear extends Animal {
honey: boolean
}
const bear = getBear()
bear.name
bear.honey
// 타입 별칭 확장
type Animal = {
name: string
}
//교집합(&)을 사용하여 확장한다.
type Bear = Animal & {
honey: Boolean
}
const bear = getBear();
bear.name;
bear.honey;
새 필드 추가
//기존 인터페이스에 새 필드 추가
interface Window {
title: string
}
//같은 이름으로 인터페이스가 선언되면 같은 이름을 가진 인터페이스는 병합된다.
interface Window {
ts: TypeScriptAPI
}
const src = 'const a = "Hello World"';
window.ts.transpileModule(src, {});
//기존 타입(이미 생성된 타입)에 새 필드 추가
type Window = {
title: string
}
type Window = {
ts: TypeScriptAPI
}
// Error: Duplicate identifier 'Window'. 타입은 이미 생성된 뒤에는 변경 될 수 없다. 즉, 병합되지 않는다.
Google 스타일 가이드
Google TypeScript Style Guide는 객체 리터럴의 type을 지정할 때 인터페이스 사용을 권한다.
interface User {
firstName: string;
lastName: string;
} // O
type User = {
firstName: string,
lastName: string,
} // X
타입스크립트의 타입 시스템은 구조적이다. 값이 타입에 필요한 모든 속성을 최소한 포함하고 속성의 타입이 재귀적으로 일치하는 경우 값은 타입과 일치한다.
형태는 거의 동일하므로 변형을 방지하기 위해 두 가지 형태중 하나만 선택한다는 원칙에 따라 하나를 선택한다.
하나 더 첨부하자면 20년 기준 타입 별칭 선언은 인라인 될 수 있는 반면 인터페이스는 항상 이름으로 참조된다는 이유도 있다.
참조
https://google.github.io/styleguide/tsguide.html#use-structural-types
https://ncjamieson.com/prefer-interfaces/