728x90
728x90

ESModules 방식과 Namespaces 방식

들어가며

  • ESModules 방식과 Namespaces 방식의 차이에 대해 간단하게 정리해본다.

 

방식

① ESModules 방식

개념

  • JavaScript 표준 모듈 시스템
  • 파일 단위로 모듈을 분리한다.
    • 각 파일이 하나의 모듈이고, 필요한 것만 @import@/@export@로 가져온다.
  • Next.js, React, TypeScript, Vite, Node.js 최신 환경은 전부 이 방식을 기본으로 사용한다.
utils/
  math.ts
components/
  Button.tsx
app/
  page.tsx

 

사용 예

//
// ☑️ [1] export
//

// utils/math.ts
export function add(a: number, b: number) {
  return a + b;
}

export const PI = 3.14;

// app/page.tsx
import { add, PI } from "@/utils/math";  // {} 로 값 뽑기

console.log(add(1, 2));
console.log(PI);

//
// ☑️ [2] default export
//

// components/Button.tsx
export default function Button() {
  return <button>Click</button>;
}

// app/page.tsx
import Button from "@/components/Button";   // 중괄호({}) 없이 가져오기

// 아래처럼 별칭 지정 가능

// components/MyComponent.tsx
export default MyComponent {}
export helloWorld = "Hello World";
export type TestType = string | number;

// app/page.tsx
import * as Test from "@/components/MyComponent";  // export default (별칭 사용)
import { helloWorld } from "@/components/MyComponent";  // export
import { helloWorld as sayHello } from "@/components/MyComponent";  // export (별칭 사용)
import { type TestType } from "@/components/MyComponent";  // 타입 불러올 때 (대부분 type 표시 필수 X)

 

② Namespaces 방식

개념

  • TypeScript 초창기에 많이 쓰던 방식
  • JavaScript의 표준 문법이 아닌 TypeScript 전용 문법
  • 하나의 전역 객체처럼 코드를 묶는 방식
  • 예전에는 브라우저에서 여러 TS 파일을 하나로 합치거나, 전역 스코프 충돌을 피하려고 @namespace@를 많이 썼다.
    • 하지만 지금은 ESModules 방식이 표준이다.

 

사용 예

namespace MathUtils {
  export function add(a: number, b: number) {
    return a + b;
  }

  export const PI = 3.14;
}

console.log(MathUtils.add(1, 2));
console.log(MathUtils.PI);

 

  • 컴파일되면 대략 다음과 같은 JavaScript 형태가 된다.
    • MathUtils라는 객체 안에 함수와 값을 넣는 구조
var MathUtils;
(function (MathUtils) {
  function add(a, b) {
    return a + b;
  }
  MathUtils.add = add;
  MathUtils.PI = 3.14;
})(MathUtils || (MathUtils = {}));

 

아직 쓰이는 경우

  • Namespaces 방식이 아직 사라진 건 아니다.
  • 아래의 경우 가끔 쓰인다.

 

(1) 타입 선언 파일 (@.d.ts@)

  • 예를 들어, 전역 타입을 확장할 때 다음과 같이 사용한다.
declare namespace NodeJS {
  interface ProcessEnv {
    MONGO_URI: string;
    NEXTAUTH_SECRET: string;
  }
}

declare namespace Express {
  interface Request {
    userId?: string;
  }
}

 

(2) 오래된 라이브러리 타입 정의

  • 일부 오래된 JS 라이브러리의 타입 선언에서 @namespace@ 키워드를 볼 수 있다.
declare namespace SomeOldLibrary {
  function init(): void;
}

 

(3) @enum@ 비슷하게 정적 그룹핑을 하고자 할 경우

  • 가능은 하지만, 보통은 객체나 모듈 @export@ 방식이 더 낫다.
// 비추천
namespace UserRole {
  export const ADMIN = "admin";
  export const USER = "user";
}

// 추천
export const USER_ROLE = {
  ADMIN: "admin",
  USER: "user",
} as const;

export type UserRole = typeof USER_ROLE[keyof typeof USER_ROLE];

 

@namespace@는 현재 주로 타입 선언 파일, 전역 타입 확장, 레거시 라이브러리 타입 정의에서 사용된다. 

 

핵심 차이 비교

구분 ESModule namespace
표준 여부 JavaScript 표준 TypeScript 표준
사용 방식 @import@ / @export@ @namespace@ 블록
기준 단위 파일 단위 객체/스코프 단위
Next.js 적합성 매우 적합 거의 비추천
Tree-shaking 유리함. 불리할 수 있음.
번들러 호환성 좋음 제한적
현대 TS 권장 여부 권장 특수 상황 제외 비권장

 

참고 사이트

 

JavaScript modules - JavaScript | MDN

 

developer.mozilla.org

 

Documentation - Namespaces

How TypeScript namespaces work

www.typescriptlang.org

 

728x90
728x90