개발새발

앰비언트 선언도 선언 병합이 된다 본문

Typescript

앰비언트 선언도 선언 병합이 된다

비숑주인 2025. 4. 11. 21:28

타입스크립트는 자바스크립트 위에 얹힌 정적 타입 시스템이다. 그렇기 때문에 자바스크립트 생태계에 존재하는 수많은 외부 라이브러리들과의 호환성을 고려해야 한다. 특히, 타입 정보가 제공되지 않는 자바스크립트 코드에 타입을 추가해야 할 때 유용한 개념이 바로 앰비언트 선언이다.

 

또한, 타입스크립트는 동일한 이름을 가진 선언을 병합할 수 있는 강력한 기능도 제공한다. 이 글에서는 앰비언트 선언과 선언 병합이 어떻게 동작하며, 실제로 어떻게 활용할 수 있는지에 대해 설명한다.

 

1. 앰비언트 선언 (Ambient Declarations)

1.1 앰비언트 선언이란?

외부 자바스크립트 코드에 타입 정보를 부여하고자 할 때 사용하는 것이 앰비언트 선언이다. declare 키워드를 사용하여 타입만 정의하고 구현부는 생략한다. 이 선언은 실제 구현이 외부에 존재한다고 타입스크립트가 믿도록 하는 장치이다.

 

declare namespace NS {
  const v: string;
}

declare enum Enum {
  ADMIN = 1,
}

declare function func(param: number): string;
declare const variable: number;

declare class C {
  constructor(p1: string, p2: string);
}

// 타입스크립트 입장에서는 문제가 없다
new C(func(variable), NS.v);

 

주의: declare로 선언한 값이 런타임에 실제로 존재하지 않으면 실행 에러가 발생한다.

 

1.2 왜 namespace, enum에 declare를 붙이는가?

  • declare namespace는 내부 멤버 구현 없이 타입만 제공할 수 있게 해준다.
  • declare enum은 컴파일 시 실제 자바스크립트 코드가 생성되지 않도록 한다.
declare namespace Lib {
  function doSomething(): void;
}

declare enum LogLevel {
  DEBUG,
  INFO,
  ERROR,
}

 

1.3 인터페이스와 타입은 declare가 필요할까?

declare interface I {}
declare type T = number;

 

 

  • 위처럼 declare로 선언할 수 있으나, 사실 생략해도 동일하게 작동한다.
  • 이유는 인터페이스와 타입 별칭은 타입 정보만 포함되기 때문이다.

 

2. 선언 병합 (Declaration Merging)

타입스크립트는 특정 타입 선언끼리 자동으로 병합하는 기능을 제공한다. 예를 들어 interface, namespace, function은 같은 이름으로 여러 번 선언되어도 자동으로 합쳐진다.

 

2.1 병합 가능한 선언 조합

선언 네임 스페이스 클래스 enum 인터페이스 타입 별칭 함수 변수
네임스페이스
클래스
인터페이스
함수

→ 널리 알려진 조합:

  • interface + interface → 속성 병합
  • namespace + namespace → 멤버 병합
  • function + namespace → 함수에 속성 부여

 

3. 실제 선언 병합 예시

3.1 클래스 + 함수 병합

declare class A {
  constructor(name: string);
}

function A(name: string) {
  return new A(name);
}

new A('sunho'); // OK
A('sunho');     // OK

 

 

  • declare class A는 타입만 정의
  • function A는 실제 구현을 제공
  • new A()와 A() 둘 다 사용 가능

 

3.2 함수 + 네임스페이스 병합

 

자바스크립트에서는 함수도 객체이므로 속성을 가질 수 있다. 타입스크립트는 이를 반영해, 함수와 네임스페이스를 병합할 수 있도록 지원한다.

 

function Ex() {
  return 'hello';
}

namespace Ex {
  export const a = 'world';
  export type B = number;
}

Ex();        // hello
Ex.a;        // world
const b: Ex.B = 123;

 

이 방식은 라이브러리 형태의 API에서 자주 활용된다. 예: jQuery(), jQuery.ajax 처럼 함수와 속성이 함께 있는 경우.

 

4. 결론

  • 앰비언트 선언은 외부 JS 코드에 타입 정보를 추가할 때 필수적인 장치이다.
  • 선언 병합은 함수, 인터페이스, 네임스페이스 등에 동일한 이름으로 기능을 확장할 수 있게 해준다.
  • 선언 병합은 강력하지만 복잡할 수 있으므로, interface, namespace, function에서만 주로 활용하고, 나머지는 이름 충돌을 피하는 것이 안전하다.
기능 목적 주의 사항
declare 구현 없이 타입만 선언 반드시 실제 런타임 값이 존재해야 함
선언 병합 여러 선언을 하나로 합침 병합 가능한 조합만 사용해야 함
function + ns 함수에 타입 정보나 속성 추가 객체처럼 함수 사용 가능