타입스크립트에서는 아래 2가지 방식으로 타입 정의를 할 수 있다.
타입 정의를 하고 추론하는데에 있어 어떤 방식을 사용해도 기능 구현에 문제가 없을테지만,
이 방식들이 어떤 특징을 가지고 있고 방식간 차이점이 무엇인지 알아보자.
이는 Object Type으로 표현 가능한 타입에 대해서만 interface로의 선언이 가능하다는 것을 의미한다.
function track(point: { x: number; y: number }) {
// ..
}
interface Point {
x: number;
y: number;
}
function track(point: Point) {
// ..
}
위의 예제에서와 같이 { x: number, y: number }
를 interface Point
로 선언하여 대체할 수 있다.
interface
는 extends
키워드를 통해 타입의 확장이 가능하다.interface Point {
x: number;
y: number;
}
interface Point3D extends Point {
z: number;
}
// 선언된 interface는 class가 구현해야 할 인터페이스 혹은 객체의 타입으로 사용이 가능하다.
class Pointer implements Point {
x = 0;
y = 1;
//...
}
const pointB: Point3D = {
x: 0,
y: 1,
z: 2,
};
function getPointer({ x, y }: Point) {
return new Pointer({ x, y });
}
interface
는 동일한 이름으로 추가 선언을 통해 병합이 가능하다.interface
갯수는 중요하지 않다. 모두 병합이 된다.interface Point {
x: number;
y: number;
}
interface Point {
z: number;
}
const pointA: Point = {
x: 0,
y: 1,
z: 3,
};
이를 선언 병합(Declaration Merging)이라고 한다.
선언 병합은 interface 뿐만아니라 namespace, enum도 같은 방식으로 선언 병합이 된다.
namespace는 class, function, enum, interface, type aliasing과도 이름이 같다면 선언 병합이 된다.
interface Point {
x: number;
y: number;
getDistance: (x: number) => number;
}
// Error: Property 'x' must be of type 'number';
interface Point {
x: string;
}
선언 병합시, 같은 이름으로 되어있는 속성 중복된다면, 타입이 변해서는 안된다.
개방 폐쇄 원칙을 준수한 것이라고 생각해도 좋을 것 같다.
interface Point {
x: number;
y: number;
equal(x: number, y: number): number;
}
interface Point {
equal({ x, y }: { x: number; y: number }): number;
}
또한, 선언 병합시, 함수 오버로드도 위와 같이 가능하다.
type Point = {
x: number;
y: number;
};
type Name = string;
type ID = string | number;
type SomeFunction = () => any;
위와 같이 string
과 같이 자바스크립트의 원시타입에 대해 별칭을 할 수 있으며, Object Type
, Union Type
에 대해서도 별칭이 가능하다.
Union Type은 2가지 이상의 다른 타입으로 구성된 타입을 말한다.
type UserInputSanitizedString = string;
function sanitizeInput(str: string): UserInputSanitizedString {
return sanitize(str);
}
let userInput = sanitizeInput(getInput());
// 문자열 할당
userInput = 'new input';
UserInputSanitizedString
는string
의 다른 이름이기 때문에 결과적으로는string
과 동일한 타입으로 추론이 되어,
위와 같이UserInputSanitizedString
의 타입으로 추론되는 변수에 다른 문자열의 할당이 가능하다.
Type Aliasing
는 intersection
을 통해 타입의 확장이 가능하다.type Animal = {
name: string;
};
type Bear = Animal & {
honey: boolean;
};
const bear = getBear();
bear.name;
bear.honey;
Type Aliasing
은 선언 병합(Declaration Merging)이 되지 않는다.Type
에 새로운 속성을 추가 할 수 없다.interface
와 가장 큰 차이라고 볼 수 있다.type Window = {
title: string;
};
type Window = {
ts: TypeScriptAPI;
};
// Error: Duplicate identifier 'Window'.
Type Aliasing
은 Object Type일 경우에 Extends
, implements
키워드와도 같이 사용이 가능하다.type Point = {
x: number;
y: number;
};
interface Point3D extends Point {
z: number;
}
class Pointer implements Point {
x = 0;
y = 1;
//...
}
타입 정의하는데 2가지의 방법과 각 특징들에 대해 알아보았다.
가장 주된 차이점은 어떤 타입을 정의할 수 있는가와 선언 병합이 되는가라고 생각한다.
타입스크립트 공식 문서에는 둘 중 하나의 선택은 개인의 취향이고, 직접적인 경험을 통해 판단하고자 한다면, type
의 기능에 대한 필요성을 느끼기 전까지 먼저 interface
를 사용하라고 한다.