Namespace(이름 공간)란 코드 조직화 메커니즘으로, pre-ES6 시절부터 논리적으로 관련된 엔티티를 결합하기 위해 사용되었습니다. 이는 클래스, 함수, 인터페이스 및 타입을 단일 이름 공간 내에 그룹화하여 이름 충돌을 피하고 코드를 더 읽기 쉽게 만들어 대규모 프로젝트를 구조화하는 데 도움을 줍니다.
문제의 역사: JavaScript ES6 표준이 등장하기 전, 개발자들은 IIFE, 객체 및 이름 공간을 사용해 모듈성을 모방했습니다. TypeScript는 코드를 그룹화하기 위해 namespace(이전에는 internal module) 키워드를 도입했습니다.
문제: 현대 모듈(ES6 Module)이 표준이 되었고, 두 접근 방식(이름 공간 및 모듈)이 동시에 존재하여 아키텍처 설계에 혼란을 야기합니다. 언제 이름 공간(namespace)을 사용하고 언제 모듈(module)을 사용하는 것이 더 좋을까요?
해결책: 이름 공간은 여전히 순수 TypeScript 프로젝트에서 보조 함수 및 타입을 그룹화하는 데 유용합니다(예: outFile 출력으로 단일 JS 파일 생성 시). 특히 npm 및 현대 빌드 도구와 함께 작업할 때는 모듈을 사용하는 것이 더 적절합니다. 이름 공간은 내부 라이브러리, 타입 선언 및 하나의 파일 내에서 구조화가 필요하거나 오래된 코드에서 자주 사용됩니다.
코드 예제:
namespace MyMath { export function add(a: number, b: number) { return a + b; } } console.log(MyMath.add(2, 3)); // 5
주요 특징:
다른 파일의 namespace를 결합하면 하나의 namespace가 될까요, 아니면 여러 개가 될까요?
TypeScript는 _declaration merging_을 수행하며, 이름이 일치할 경우 이름 공간의 서로 다른 부분이 올바르게 연결되고 동일한 범위에 있는 경우 하나로 합쳐집니다.
// mathA.ts namespace MathUtil { export function sum(a: number, b: number) { return a + b; } } // mathB.ts namespace MathUtil { export function mul(a: number, b: number) { return a * b; } } // 컴파일 후 MathUtil은 두 메서드를 포함합니다.
namespace를 모듈처럼 import/require할 수 있을까요?
아니요, namespace는 기본 내보내기/이름 내보내기가 없으며, ES6 표준 구문으로 가져올 수 없습니다. Namespace는 순수 TypeScript 개념으로, JavaScript 모듈로 변환되지 않습니다.
다른 파일에서 import를 통해 namespace의 값을 가져올 수 있나요?
아니요, 다른 파일에서 namespace에 접근하려면 reference(/// <reference path="..." />)를 사용해야 하며, outFile로 컴파일해야 합니다. import를 통한 가져오는 것은 불가능합니다.
오래된 프로젝트에서 로직을 수십 개의 namespace로 나누었고, 동일한 이름이 여러 파일에 나타나면서 예상치 못한 결합이나 충돌이 발생했습니다. 모듈 아키텍처로 전환하면서 코드 이식이 매우 힘들어졌습니다.
장점:
단점:
큰 라이브러리에서 namespace 선언을 통해 index.d.ts 파일에 API를 선언하여 모든 타입과 인터페이스를 구현 코드 없이 통일시켰습니다. 이를 통해 라이브러리의 소비자를 신속하게 유형화하고 팀 간의 계약을 쉽게 업데이트할 수 있었습니다.
장점:
단점: