Menu

TypeScript namespace(네임스페이스)란? 언제 쓰는가

TypeScript namespace는 값과 타입을 하나의 이름 아래 묶고 평범한 객체로 컴파일됩니다. 문법, 네임스페이스끼리 또는 함수, 클래스와 병합되는 방식, ES 모듈이 네임스페이스를 대체한 이유, 그리고 아직 네임스페이스를 만나는 곳인 선언 파일과 전역 확장을 알아봅니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

네임스페이스는 함수, 상수, 타입을 하나의 이름 아래 묶는 이름 붙은 블록입니다. export로 표시한 멤버는 Name.member로 접근할 수 있고, 나머지는 블록 안에서만 보입니다. 실행 시점에 네임스페이스는 평범한 객체입니다.

네임스페이스는 무엇으로 컴파일되나

네임스페이스는 코드를 생성하는 몇 안 되는 TypeScript 기능 중 하나입니다. 위 블록은 객체를 채우는 함수가 됩니다.

var Geometry;
(function (Geometry) {
    const TAU = Math.PI * 2;
    function circumference(radius) {
        return TAU * radius;
    }
    Geometry.circumference = circumference;
    function area(radius) {
        return Math.PI * radius ** 2;
    }
    Geometry.area = area;
})(Geometry || (Geometry = {}));

모듈이 생기기 전에 JavaScript 코드가 모든 이름을 전역 스코프에 두지 않으려고 쓰던 패턴입니다. TAU는 함수의 지역 변수이므로 다른 코드에서 볼 수 없습니다. 읽으려고 하면 컴파일 오류가 납니다.

컴파일러는 index.ts(10,17): error TS2339: Property 'rate' does not exist on type 'typeof Tax'.를 보고합니다. const rate 앞에 export를 붙이면 두 줄 모두 실행됩니다.

중첩, 병합, 별칭

네임스페이스는 중첩할 수 있고, 이름이 같은 두 블록은 하나로 병합됩니다. 출력의 Geometry || (Geometry = {})가 이를 가능하게 합니다. 두 번째 블록이 기존 객체에 멤버를 추가하는 것입니다. import X = A.B는 짧은 별칭을 만듭니다.

namespace A.B.C { }는 중첩된 세 블록의 축약형입니다. 예전 표기인 module Shop { }도 같은 뜻이지만 지금은 TS1540 오류 A 'namespace' declaration should not be declared using the 'module' keyword. Please use the 'namespace' keyword instead.로 거부됩니다.

함수, 클래스와 병합하기

네임스페이스는 함수, 클래스, enum과 이름을 공유하며 멤버를 추가할 수 있습니다. 프로퍼티도 가진 함수나, 헬퍼가 붙은 클래스를 기술하는 가장 깔끔한 방법은 여전히 이것입니다.

클래스라면 static 메서드가 같은 일을 하며 순수한 JavaScript입니다. 함수라면 네임스페이스 없이 선언 바로 뒤에 format.prefix = "$"를 대입해도 됩니다. TypeScript는 그렇게 대입한 프로퍼티를 추적합니다.

네임스페이스와 모듈 비교

ES 모듈 이전에는 큰 TypeScript 프로그램이 전역 네임스페이스를 공유하는 여러 스크립트 파일로 이루어졌고, /// <reference path="..." />로 이어 붙여 outFile로 한 파일에 컴파일했습니다. 모듈이 이를 대체했습니다. 각 파일은 자기 스코프를 가지고, 의존성은 명시적인 import이며, 번들러는 쓰이지 않는 export를 제거할 수 있습니다. TypeScript 7에서 outFile이 제거되었으므로(TS5102 오류) 여러 파일에 걸친 네임스페이스 구성은 더 이상 빌드 선택지가 아닙니다.

네임스페이스모듈
단위파일 안의 이름 붙은 블록파일 자체
스코프모듈 안이 아니면 전역항상 독립적
의존성불러오는 순서에 따른 암묵적 의존명시적 import
출력함수가 만드는 객체import/export 또는 require
쓰이지 않는 코드 제거번들러가 모든 멤버를 유지번들러가 쓰이지 않는 export를 제거 가능
Node 타입 제거로 실행타입만 담은 경우에만예

모듈 안에서 모든 것을 네임스페이스로 감싸면 아무 이득 없이 이름 단계만 하나 늘어납니다. import하는 쪽은 Utils.Utils.format이라고 써야 합니다. 함수를 직접 export하고, 접두어가 필요하면 import하는 쪽에서 import * as Utils from "./utils.js"를 고르게 하세요.

아직 네임스페이스를 만나는 곳

선언 파일은 전역 객체 하나를 노출하는 라이브러리를 기술하거나 타입을 묶을 때 네임스페이스를 씁니다.

// jquery-like.d.ts: a global function that also has properties
declare function $(selector: string): unknown;
declare namespace $ {
    const version: string;
    function ajax(url: string): Promise<unknown>;
}

타입 패키지는 확장할 수 있는 타입을 노출할 때 네임스페이스를 씁니다. @types/node는 namespace NodeJS를 선언하며, 어느 모듈에서든 그 안의 ProcessEnv 인터페이스에 추가하려면 declare global이 필요합니다.

// env.d.ts
export {};

declare global {
    namespace NodeJS {
        interface ProcessEnv {
            API_URL: string; // process.env.API_URL is now string, not string | undefined
        }
    }
}

병합된 네임스페이스 안의 인터페이스도 병합되며, 이 덕분에 위와 같은 확장이 동작합니다.

네임스페이스와 타입 제거

Node 24는 타입 문법을 지워서 .ts 파일을 실행합니다. 값을 담은 네임스페이스는 지울 수 없고 위에서 본 객체로 컴파일되어야 하므로, node app.ts는 다음과 같이 멈춥니다.

SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript namespace declaration is not supported in strip-only mode

완전히 사라지는 두 종류의 네임스페이스는 괜찮습니다. declare namespace와, 멤버가 모두 타입이나 인터페이스인 네임스페이스입니다. 컴파일러 옵션 erasableSyntaxOnly: true는 나머지를 컴파일 시점에 TS1294 오류 This syntax is not allowed when 'erasableSyntaxOnly' is enabled.로 보고하며, 타입 제거로 실행하는 프로젝트는 이렇게 네임스페이스를 막습니다. node --experimental-transform-types는 실험적 기능 경고와 함께 네임스페이스를 컴파일합니다.

자주 묻는 질문

TypeScript에서 네임스페이스와 모듈 중 무엇을 써야 하나요?

새 코드에는 모듈(import와 export)을 쓰세요. 모든 파일이 이미 자기 스코프를 가지고, 번들러와 Node가 모듈을 이해하며, 쓰이지 않는 export를 제거할 수 있습니다. 네임스페이스는 선언 파일, 전역 확장, 그리고 같은 이름의 함수나 클래스에 타입이나 헬퍼를 붙일 때 여전히 유용합니다.

TypeScript 네임스페이스는 무엇으로 컴파일되나요?

즉시 실행 함수가 채우는 객체로 컴파일됩니다: var Geometry; (function (Geometry) { Geometry.circle = circle; })(Geometry || (Geometry = {}));. export한 멤버는 그 객체의 프로퍼티가 되고, export가 없는 멤버는 함수 안의 지역 변수로 남습니다.

TypeScript에서 namespace와 module의 차이는 무엇인가요?

모듈은 최상위에 import나 export가 있는 파일입니다. 네임스페이스는 파일 안의 이름 붙은 블록입니다. 예전 TypeScript는 네임스페이스를 "내부 모듈"이라 부르며 module Foo {}를 허용했지만, 지금 그 표기는 TS1540 오류이고 namespace Foo {}만 받아들입니다.

Node는 네임스페이스를 쓰는 TypeScript 파일을 실행할 수 있나요?

기본 타입 제거(type stripping)로는 안 됩니다. 값을 담은 네임스페이스는 ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX를 냅니다. 타입 제거는 타입을 지우기만 하는데 네임스페이스에는 생성된 코드가 필요하기 때문입니다. 타입만 담은 네임스페이스와 declare namespace는 지워지므로 문제없이 실행됩니다.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기