앰비언트 모듈 선언
앞선 8.1절과 8.2절에서 .d.ts
파일이 무엇이고 어떻게 작성하는지 기본적인 내용을 살펴보았습니다. 그중에서도 declare
키워드를 사용하여 타입 정보만을 선언하는 것을 앰비언트 선언(Ambient Declarations) 이라고 부릅니다. 그리고 이 앰비언트 선언 중에서도 특정 모듈의 타입을 정의하는 것이 바로 앰비언트 모듈 선언(Ambient Module Declarations) 입니다.
앰비언트 모듈 선언은 주로 두 가지 경우에 사용됩니다.
- 타입스크립트 프로젝트에서 타입 정의가 없는 자바스크립트 모듈을 사용할 때.
- 웹팩(Webpack)이나 Vite 같은 번들러를 사용할 때 자바스크립트가 아닌 파일(예: 이미지, CSS 파일) 을 모듈처럼
import
할 때.
이 절에서는 앰비언트 모듈 선언의 구체적인 사용법과 중요성에 대해 더 깊이 알아보겠습니다.
declare module 'module-name'
구문
앰비언트 모듈 선언의 핵심은 declare module 'module-name'
구문입니다. 여기서 'module-name'
은 import
문에서 사용될 모듈의 이름 또는 경로를 나타냅니다.
// Example: some-legacy-library.d.ts
declare module 'some-legacy-library' {
// 이 블록 안에 'some-legacy-library' 모듈의 타입을 정의합니다.
export interface Options {
debugMode: boolean;
logLevel: 'info' | 'warn' | 'error';
}
export function initialize(options: Options): void;
export function fetchData<T>(url: string): Promise<T>;
export const version: string;
// 기본(default) 내보내기가 있다면 이렇게 선언합니다.
export default class SomeClient {
constructor(apiKey: string);
sendRequest(data: any): Promise<any>;
}
}
위 some-legacy-library.d.ts
파일을 프로젝트에 포함시키면, 이제 다른 타입스크립트 파일에서 이 라이브러리를 타입 안전하게 가져와 사용할 수 있습니다.
// app.ts
import { initialize, fetchData, version } from 'some-legacy-library';
import SomeClient from 'some-legacy-library'; // default export 가져오기
initialize({ debugMode: true, logLevel: 'info' });
console.log(`Library Version: ${version}`);
async function loadData() {
const data = await fetchData<{ name: string; value: number }>('/api/data');
console.log(data.name, data.value);
}
const client = new SomeClient('my-api-key');
client.sendRequest({ type: 'report' });
// initialize({}); // Error: 'Options' 형식에 'debugMode' 및 'logLevel' 속성이 없습니다.
컴파일러는 import 'some-legacy-library'
구문을 만나면, node_modules
에서 실제 some-legacy-library
모듈을 찾는 것 외에도, 해당 모듈 이름에 해당하는 .d.ts
파일을 찾아 타입 정보를 얻습니다. @types
패키지를 설치하는 것이 바로 이 앰비언트 모듈 선언 파일을 프로젝트에 추가하는 과정입니다.
와일드카드 모듈 선언
특정 파일 확장자를 가진 모든 파일에 대해 공통된 타입을 선언하고 싶을 때 와일드카드 문자 (*
) 를 사용할 수 있습니다. 이는 이미지, CSS, JSON 등 웹팩과 같은 번들러가 모듈처럼 처리하는 비-자바스크립트/타입스크립트 파일을 임포트할 때 특히 유용합니다.
// types/custom-file-types.d.ts 또는 src/declarations.d.ts
declare module '*.png' {
const value: string; // 일반적으로 이미지 파일은 번들링 후 URL 문자열로 처리됩니다.
export default value;
}
declare module '*.svg' {
// SVG 파일을 React 컴포넌트로 가져오는 경우 (예: @svgr/webpack)
import * as React from 'react';
export const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement> & { title?: string }>;
const src: string;
export default src;
}
declare module '*.css' {
const content: { [className: string]: string }; // CSS Module을 사용하는 경우
export default content;
}
declare module '*.json' {
const value: any; // JSON 파일은 객체로 직접 로드될 수 있습니다.
export default value;
}
이제 이 선언 파일이 프로젝트에 포함되면, 다음과 같이 해당 확장자의 파일을 타입 오류 없이 가져올 수 있습니다.
// app.ts
import logo from './assets/logo.png'; // logo의 타입은 string
import Icon from './assets/icon.svg'; // Icon은 ReactComponent, 기본 export는 src (string)
import styles from './styles/main.css'; // styles의 타입은 { [className: string]: string }
console.log(logo); // 예: "/static/media/logo.9259f60f.png"
if (Icon.ReactComponent) {
// React 컴포넌트로 사용 가능
}
console.log(styles.container); // 예: "main_container__abc123"
와일드카드 모듈 선언은 번들러 환경에서 파일 기반의 에셋을 모듈처럼 다룰 때 발생하는 타입 오류를 해결하는 표준적인 방법입니다.
전역 모듈과 스크립트 파일의 앰비언트 선언
간혹 모듈 시스템을 사용하지 않고 전역 스코프에 변수나 함수를 노출하는 자바스크립트 파일(스크립트 파일)의 타입을 선언해야 할 때가 있습니다. 이 경우 declare module
대신 declare namespace
또는 단순히 declare var
/function
/class
를 사용합니다.
전역 스크립트 타입 선언 (global-script-types.d.ts
)
// global-script-types.d.ts
// 이 파일은 HTML <script> 태그로 로드되는 자바스크립트 파일에 대한 타입 정의입니다.
// 전역 변수 선언
declare var MY_APP: {
version: string;
debugMode: boolean;
};
// 전역 함수 선언
declare function initializeApp(config: { theme: string }): void;
// 전역 객체 확장 (예: window 객체에 추가되는 속성)
interface Window {
_paq?: Array<any>; // Matomo (Piwik) 같은 분석 스크립트가 추가하는 전역 변수
}
// 네임스페이스를 사용하여 관련된 전역 객체를 그룹화
declare namespace MyGlobalUtils {
function formatCurrency(amount: number): string;
class DataLoader {
load(url: string): Promise<any>;
}
}
이러한 파일들은 declare module
구문으로 감싸져 있지 않기 때문에, 해당 .d.ts
파일이 프로젝트에 포함되면 선언된 모든 타입이 전역 스코프에 추가됩니다.
앰비언트 모듈 선언의 중요성
- 타입 안전성 확보: 자바스크립트 라이브러리나 외부 리소스에 대한 타입 정보를 제공하여, 타입스크립트 컴파일러가 잠재적인 오류를 잡아내고 코드 자동 완성을 제공할 수 있도록 합니다.
- 개발 생산성 향상: IDE의 자동 완성, 매개변수 힌트, 타입 오류 검출 등의 기능을 활용하여 개발자가 더 빠르고 정확하게 코드를 작성할 수 있게 합니다.
- 유지보수성 증대: 타입 정보를 통해 코드의 의도와 기대되는 데이터 형태를 명확히 하여, 다른 개발자가 코드를 이해하고 변경하기 쉽게 만듭니다.
- 레거시 코드 통합: 기존 자바스크립트 코드베이스를 타입스크립트로 점진적으로 전환할 때, 핵심적인 역할을 합니다.
앰비언트 모듈 선언은 타입스크립트가 방대한 자바스크립트 생태계와 조화롭게 공존할 수 있게 하는 핵심 메커니즘입니다. declare module 'module-name'
과 와일드카드 선언(*.ext
)을 통해 외부 모듈의 타입을 명확히 정의함으로써, 타입스크립트의 강력한 타입 검사 기능을 자바스크립트 프로젝트 전반에 걸쳐 확장할 수 있습니다.