development

타입스크립트 인터페이스 선언 머지 (Interface Declaration Merging)

나는산타 2022. 12. 1. 14:44
반응형

Typescript Interface Declaration Merging 정리

 

타입스크립트에서 기존 인터페이스를 업데이트해야 하는 경우도 있지만, 그 외의 장소에서의 사용 방법을 변경하는 경우는 할까?

 

인터페이스 선언 병합

Interface Declaration Merging을 사용하면 동일한 이름의 인터페이스가 두 개 있을 때마다 타입스크립트 컴파일러는 두 인터페이스의 속성을 양쪽이 공유하는 이름의 단일 인터페이스로 병합하려고 한다. 타입스크립트를 사용하면 interfacesenumsnamespaces 등 여러 유형을 병합할 수 있습니다. 한 가지 주목할 만한 예는 클래스를 통합할 수 없다는 것이다. 그러기 위해서는 Mixins을 사용해야 한다.

 

인터페이스 선언 병합의 예

코드 예제를 사용하여 발생할 수 있는 모든 병합 케이스에 대해 설명한다.

interface Car {
  model: string;
  engineSize: number;
}

interface Car {
  manufacturer: string;
}

interface Car {
  color: string;
}

const car: Car = {
  color: 'red',
  engineSize: 1968,
  manufacturer: 'BMW',
  model: 'M4',
  numSeats: 4, // `numSeats` property is not specified
};

 

선언된 모든 인터페이스는 동일한 이름을 공유하기 때문에 이러한 인터페이스는 모두 집합 속성을 공유하면서 고유의 이름으로 병합된다. 또, 동일한 명칭을 가지는 모든 속성은, 동일한 종류여야 한다. 그 외의 경우는 다음 예시와 같이 컴파일 오류가 발생한다.

 

interface Car {
  model: string;
  engineSize: number;
}

interface Car {
  manufacturer: string;
}

interface Car {
  color: string;
  numSeats: string;
}

interface Car {
  numSeats: number; // Error: Subsequent property declarations must have the same type.  Property 'numSeats' must be of type 'string', but here has type 'number'.ts(2717)
}

const car: Car = {
  color: 'red',
  engineSize: 1968,
  manufacturer: 'BMW',
  model: 'M4',
  numSeats: 4,
};

 

그런 다음 함수 유형과 동일한 속성 이름을 가진 인터페이스를 조사한다.

 

interface Car {
  model: string;
  engineSize: number;
  manufacturer: string;
  color: string;
}

interface Car {
  start(param: string);
}

interface Car {
  start(param: number);
}

const bmw: Car = {
  model: 'M4',
  manufacturer: 'BMW',
  engineSize: 2993,
  color: 'white',
  start: (param) => param,
};

bmw.start(2) // `start(param: number)` will be used
bmw.start('3') // `start(param: string)` will be used

 

동일한 구조를 갖는 기능을 포함하는 인터페이스가 병합되면 마지막으로 선언된 인터페이스의 기능이 병합된 인터페이스의 상단에 표시되며, 첫 번째 인터페이스에서 선언된 기능은 다음과 같이 표시된다.

 

interface Car {
  start(param: string);
}

interface Car {
  start(param: any);
}

interface Car {
  start(param: number);
  start(param: boolean);
}

// This is how the final merged interface looks like
interface Car {
  // functions in the last interface appear at the top
  start(param: number);
  start(param: boolean);

  // function in the middle interface appears next
  start(param: any): number;

  // function in the first interface appears last
  start(param: string): string;
}

 

그 이유는 나중에 선언된 인터페이스가 처음 선언된 인터페이스보다 우선순위가 높기 때문이다. 위의 예를 고려하면 최종 병합된 Car 인터페이스에서는 start(param:any):number 메서드 선언이 start(param:string) 앞에 오기 때문에 start(param:string):string 메서드 선언은 임의의 유형을 나타낼 수 있으므로 start(param:string)는 인수로 전달되어도 호출되지 않는다. 이것은 같은 이름의 함수 파라미터가 문자열 리터럴을 유형으로 가지는 경우를 제외하고 모든 인터페이스에 적용된다. 위와 같은 순서를 따르지만 문자열 리터럴 타입의 함수가 우선이기 때문에 Declaration Merging에 의해 상위에 표시된다. 위에서 설명한 바와 같이 나중 인터페이스의 문자열 리터럴은 첫 번째 인터페이스 앞에 표시된다.

 

 

 

 

반응형