Back to the Basics

[typescript] Type VS Interface 본문

Language/Typescript & NestJS

[typescript] Type VS Interface

9Jaeng 2024. 1. 7. 18:50
728x90
반응형
반응형

ts 공부를 하던 중 문득 궁금한 것이 생겼다.

type 과 Interface는 둘 다 type을 정의할 때 사용될 수 있고 사용한다. 그럼 언제 type을 사용하고 언제 interface를 사용할까?

이를 확인해보기 위해 type과 interface 의 공통적인 부분화 다른 부분을 알아보고 언제 무엇을 사용하는 것이 좋은지 알아보자

type과 interface 공통적인 부분

1. type과 interface 둘 다 객체를 만들 수 있다.

type TAnimal = {
  name: string;
  age: number;
  speak?: () => void;
};

const dog: IAnimal = {
  name: '구쟁',
  age: 1,
  speak: () => console.log('멍멍'),
};

const cat: TAnimal = {
  name: '쟁기',
  age: 2,
  speak: () => console.log('야옹'),
};

각각을 타입으로 하는 object 생성이 가능하다.

2. Class에서 Implements & extend 가 가능하다

class Cat implements IAnimal {
  constructor(public name: string, public age: number) {}
}

class Dog implements TAnimal {
  constructor(public name: string, public age: number) {}
}

위와 같이 class를 만들 때 type과 interface 둘 다 implemtns를 할 수 있따.
그리고 아래와 같이 extend도 가능하다.
하지만 구문은 다르다. interfaces는 extend 키워드를 사용하지만 type은 intersection 을 사용하여 extend기능이 가능하다

// Interface extends interface
interface IOtherAnimal extends IAnimal {
  isSwimming: boolean;
}

// Interface extends type alias
interface IOtherAnimal extends TAnimal {
  isSwimming: boolean;
}


// Type alias extends type alias
type TOtherAnimal = TAnimal & {
  isSwimming: boolean;
};

// Type alias extends interface
type TOtherAnimal = IAnimal & {
  isSwimming: boolean;
};

3. function type

표현 형식은 다르지만 interface와 type aliase 모두 function에 대한 타입을 지정할 수 있다

type TFunc = (num1: number, num2: number) => number;

interface IFunc {
  (num1: number, num2: number): number;
}

표현 형식으로 보면 type alise가 더 간결해보이긴한다

이렇게 놓고 보면 Interface, type 둘 다 비슷한 성격을 갖고있고 서로 교차해서 사용할 수도 있어보인다.
type aliase 하나만 사용해도 Primitive types을 정의할 수도 있고 위와 같이 interface를 대신할 수도 있어보인다. 둘을 구분해서 사용해야하는 경우가 있을까?? 어떤 차이점이 있는지 알아보자

type과 interface 다른 부분

Only type

interface와는 다르게 type aliase는 아래와 같이 타입을 만들 수 있다.
이렇게 타입은 interface와는 다르게 복잡한 타입 또한 만들 수 있다.

  1. primative type
    // primitive
    type Name = string;
    
    // object
    type PartialPointX = { x: number; };
    type PartialPointY = { y: number; };
    
    // union
    type PartialPoint = PartialPointX | PartialPointY;
    
    // tuple
    type Data = [number, string];
    복잡한 타입을 만들 수 있기 때문에 function type또한 type aliase를 사용하는 경우가 많다고 한다.
    이런 다른 사이트에서 가져온 예시인데 이런 복잡한 타입의 경우 interface로는 불가능하다
type Car = 'ICE' | 'EV';
type ChargeEV = (kws: number)=> void;
type FillPetrol = (type: string, liters: number) => void;
type RefillHandler<A extends Car> = A extends 'ICE' ? FillPetrol : A extends 'EV' ? ChargeEV : never;
const chargeTesla: RefillHandler<'EV'> = (power) => {
    // Implementation for charging electric cars (EV)
};
const refillToyota: RefillHandler<'ICE'> = (fuelType, amount) => {
    // Implementation for refilling internal combustion engine cars (ICE)
};
  1. implements or extend가 union type의 경우 불가능하다

위에 예시를 들었던 것 처럼 object type의 경우는 가능했다 하지만 아래와 같이 union type의 경우 불가능하다
"클래스는 개체 형식 또는 정적으로 알려진 멤버가 포함된 개체 형식의 교집합만 구현할 수 있습니다.ts(2422)" 라는 경고가 뜬다

type PartialPoint = { x: number; } | { y: number; };

class SomePartialPoint implements PartialPoint {
  x = 1;
  y = 2;
}
  1. Type의 key를 이용할 수도 있다
    아래와 같이 정의된 Cat type의 key릐 타입을 사용할 수도 있다
type Cat= {
  name: string;
  age: number;
};

type Name = Cat["name"];

Only Interface

  1. Declaration merging
    해석하면 선언 병합 ? 요건 ts 공식문서를 통해 보면 typescript에만 있는 개념이라고 한다.
    뭔지 간략하게 적어보자면 .. 인터페이스를 여러 번 정의하면 TypeScript 컴파일러는 이러한 정의를 단일 인터페이스로 병합하는 것이라고 한다
    하지만 type aliase는 불가능하다

공식문서의 예제를 가져와봤다

interface Box {
  height: number;
  width: number;
}
interface Box {
  scale: number;
}
let box: Box = { height: 5, width: 6, scale: 10 };

interface만 가능한 것은 declareation merging 하나가 제일 큰 특징인 것 같다. 이걸 얼마나 자주 쓸지는 모르겠다.
비교 결과 type aliase는 union type의 경우 extend를 하지 못한다는 것과 같은 이름의 type을 declareation merging을 하지 못한다는 부분은 불가능 하다는 것을 알 수 있다. 확실히 declareation merging 을 사용하는 경우는 확장성이 용이할 것 같긴한데.. 라이브러리 확장이나 글로벌 타입 정의에 유용하다 고는 하는데 얼마나 잘 쓰일지는 실전에서 사용해봐야 알 수 있으르 것 같다.

사실살 이렇게 비교해 보아도 type은 interface를 충분이 대체할 수 있을 것 같기는 하다. 하지만 찾아봤던 많은 글에서 그랳듯이 개념상의 차이가 존재하고 이미 넓게 형성된 커뮤니티에서 사용하는 방식에서 class의 구현이나 객체의 타입정의의 경우 interface를 더 많이 사용하는 것 같다.

개념상의 차이점

  • Interface :
    • Interface는 규격사항 이며, OBJ - OBJ 의사소통을 Interface를 토대로 상호작용
    • Interface의 규격을 구현 함으로써 동일한 규격서를 따라간다고 할 수 있다
    • 어떤 특정 규격을 정의하는 것이라면 type을 쓰는것은 적절하지 않다. (누군가 구현을 하는 경우)
  • Types
    • DATA의 타입을 결정하는 것
    • Position이라는 Type의 경우 어떠한 데이터를 담고있는 모습이다.
    • 이렁 경우 type을 쓰는 것이 적절
    • interface를 쓰는 경우 이것을 구현하는 Class가 있는지 생각하게 된다.
    • 데이터를 담을 목적으로 만들때에는 type을 쓰는 것이 좋다

음 이런 개념상의 차이를 두고 구분되어 사용하는 것이 best case같다.

마지막으로 아래는 ts 공식문서에서 정의한 type과 interface에 대한 간략한 설명이다.

interface and type 설명 출처 공식문서

 

728x90
반응형
Comments