Skip to content

Instantly share code, notes, and snippets.

@DublinCity
Last active July 6, 2022 01:32
Show Gist options
  • Save DublinCity/f40bcd60361d5ae62f33ce2f501e3e42 to your computer and use it in GitHub Desktop.
Save DublinCity/f40bcd60361d5ae62f33ce2f501e3e42 to your computer and use it in GitHub Desktop.
Item13: 타입과 인터페이스

Item13: 타입과 인터페이스의 차이

타입스크립트에서 타입을 정의하는 방법은 type, interface 두 가지가 있다. 대부분의 경우 타입 또는 인터페이스를 사용해도 된다. 하지만 타입과 인터페이스 사이에 존재하는 차이를 분명하게 알고, 같은 상황에서는 동일한 방법으로 명명된 타입을 정의해 일관성을 유지해야한다.

타입과 인터페이스 모두 가능한 것

잉여속성체크

interface IPerson {
	name: string
}
type TPerson = { name: string }
const iperson: IPerson = { name: 'koo', age: 15 } // Type Error
const tperson: TPerson = { name: 'koo', age: 15 } // Type Error

인덱스 시그니처

type TDict = { [key: string]: string }
interface IDict {
  [key: string]: string
}

함수 시그니처

type TFn = (x: number) => void
interface IFn {
  (x: number) => void
}

추가속성이 있는 함수 시그니처

type TFn = {
  (x: number) => void
  props: string
}
interface IFn {
  (x: number) => void
  props: string
}

Generic

type TFn<T> = {
  props: T
}
interface IFn<T> {
  props: T
}

확장

인터페이스는 타입을 확장할 수 있고, 타입은 인터페이스를 확장할 수 있다.

type A  = { name: string }
interface B { age: string }

interface C extends A { }
type D = B & A

타입을 사용해야하는 경우

union

인터페이스에는 union 이라는 개념이 없다. 따라서 인터페이스는 union type 을 확장할 수 없다.

type A  = { name: string }

type B  = { age: string }

type ABUnion = A | B
type ABIntersection = A & B

interface D extends ABIntersection { }
interface E extends ABUnion { } // Type Error 

따라서 아래와 같은 타입은 인터페이스로 표현할 수 없다.

type NamedVariable = ({a: string} | {b: string}) & {name: string}

tuple

tuple 은 인터페이스로 구현할 수는 있지만 타입으로 구현하는 것이 좋다.

type TPair = [number, number]
interface IPair {
  0: number
  1: number
  length: 2
}

인터페이스를 사용해야하는 경우

보강(augment)

아래의 코드를 보면 인터페이스가 중복으로 선언된 것 같지만 올바른 문법이고 아래처럼 속성을 확장하는 것을 선언병합(declaration merging) 이라고 한다.

interface A { name: string }
interface A { age: number }
const person: A = { name:'koo', age: 15 }

선언 병합은 주로 타입 선언 파일에서 사용되고 타입 선언 파일을 작성할 때는 선언 병합을 지원하기 위해서 반드시 인터페이스를 사용해야한다.

예를 들면 Array 인터페이스는 lib.es5.d.ts 에 정의되어있는데, tsconfig.jsonlib 목록에 es2015 를 추가하면 타입스크립트는 lib.es2015.d.ts 에 선언된 인터페이스를 병합한다. 여기에는 ES2015에 추가된 find 같은 매서드가 포함된다. 결과적으로 각 선언이 병합되어 전체 매서드를 가지는 Array 타입을 가지게 된다.

하지만 프로젝트 내부적으로 사용되는 타입에 선언 병합을 한다면 잘못된 설계임을 기억하자.

결론

  • 인터페이스로 표현할 수 없는 유니온의 경우 타입으로 선언
  • 타입과 인터페이스 둘다 표현가능하다면, 기존 코드와 일관되게 표현
  • 어떤 외부 API에 대한 타입을 보강한다면 반드시 인터페이스를 사용
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment