(TS) 전역 변수 타입 선언하기

Jan 06, 2025

TL;DR

순수 타입스크립트, Next.js 환경에서의 사용법:

global.d.ts
/* eslint-disable no-var */

export {};

declare global {
  var myGlobalVar: string;

  interface Window {
    myCustomVar: string;
  }
}ts

Vite 기반 프레임워크(Nuxt, SvelteKit, Astro)에서의 사용법:

vite-env.d.ts
/// <reference types="vite/client" />

const myGlobalVar: string;

interface Window {
  myCustomVar: string;
}ts

들어가면서

타입스크립트로 개발하다 보면 전역 변수의 타입을 선언해야 할 때가 있습니다.
기본 선언 방법부터 간단한 활용 예시를 살펴봅시다.

타입 선언 방법

타입스크립트에서 전역 변수의 타입은 declare를 통해서 선언할 수 있습니다.
참고로 VSCode 같은 IDE에서 이렇게 선언된 타입을 참고하여 코드 자동 완성을 지원해줍니다.

declare var var myGlobalVar: stringmyGlobalVar: string;

myG
  • myGlobalVar
;
//
ts

만약 타입을 여러 파일에 적용시키려면, 네 가지 디테일을 확인하면 좋을 것 같습니다.

첫째는 declare global {}안에 타입을 선언하는 것입니다.

declare global {
  var myGlobalVar: string;
}ts

둘째는 .d.ts 확장자 파일에서 타입을 선언하는 것입니다.
해당 파일은 오로지 타입 정의만을 위한 것임을 명시하여, 관심사를 분리할 수 있어 코드를 보다 더 쉽게 관리할 수 있게 됩니다. 자세한 내용은 조금 다른 타입스크립트 .d.ts 포스트를 참고바랍니다.

global.d.ts
declare global {
  var myGlobalVar: string;
}ts

셋째는 파일 최상단에 export {};를 추가하는 것입니다.
이는 타입스크립트 파일에 import/export 구문이 있어야 타입스크립트 컴파일러는 해당 파일을 모듈 스크립트(type=“module”)로 인식하게 되기 때문입니다. 만약 이 구문이 없다면 컴파일러는 이 파일을 일반 스크립트(type=“text/javascript”)로 간주하게 되어, 선언된 타입을 다른 파일에서 사용할 수 없게 됩니다.

global.d.ts
export {};

declare global {
  var myGlobalVar: string;
}ts

넷째는 tsconfig.json에서 해당 파일이 include되어야 동작한다는 것입니다.
타입스크립트 컴파일러가 해당 파일을 참조해야 의도대로 타입이 추론됩니다. .d.ts 파일도 .ts로 끝나기에 보통 **/*.ts 같은 패턴으로 포함시키면 됩니다. 만약 특정 경로에 타입 정의 파일이 있다면 해당 경로를 명시적으로 추가해주는 것이 좋습니다.

tsconfig.json
{
  "compilerOptions": {
    "skipLibCheck": true,
    //...truncated...
  },
  "include": ["**/*.ts"],
  "exclude": ["node_modules"],
}jsonc

ESLint의 no-var 규칙 대응

ESLint의 no-var 규칙으로 인해 Unexpected var 오류가 표기될 수 있습니다.

export {};

declare global {
  var myGlobalVar: string;
Unexpected var, use let or const instead. (no-var)
}
ts

var 대신 const를 사용하면 ESLint 오류가 해소되지만, IDE에서 전역 객체에서 해당 변수를 알지 못하게 되어 타입 추론에 오류가 발생하게 됩니다.

이는 var의 경우 전역 스코프에서 선언하면 자동으로 전역 객체의 속성으로 할당되는 반면에, letconst블록 스코프를 가지기에 전역 스코프에서 선언해도 전역 객체의 속성으로 추가되지 않습니다.

자바스크립트 언어 특성상 어쩔 수 없이 var를 사용해야 하기에, 해당 파일에선 no-var 규칙을 무시하는 것을 추천합니다.

/* eslint-disable no-var */

export {};

declare global {
  var myGlobalVar: string;
}ts

window

브라우저에서의 전역 객체인 window에 타입을 확장하려면 declare global 안에서 Window 인터페이스를 명시하면 됩니다.

global.d.ts
export {};

declare global {
  interface Window {
    /**
     * 커스텀 변수 설명
     */
    Window.myCustomVar: string
커스텀 변수 설명
myCustomVar
: string;
} } /// ---cut--- var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
log
(var window: Window & typeof globalThis
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/window)
window
.Window.myCustomVar: string
커스텀 변수 설명
myCustomVar
);
ts

global, globalThis

global는 Node.js에서의 전역 객체입니다.
globalThis는 ESM에서의 전역 객체에 대한 참조입니다. ES2020에서 도입된 표준으로, 브라우저와 Node.js 등 모든 자바스크립트 런타임에서 동일하게 동작합니다.

declare global로 타입을 선언하면 똑같이 적용이 됩니다.

global.d.ts
export {};

declare global {
  /**
   * 커스텀 변수 설명
   */
  var var myGlobalThisVar: string
커스텀 변수 설명
myGlobalThisVar
: string;
} /// ---cut--- var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
log
(var myGlobalThisVar: string
커스텀 변수 설명
myGlobalThisVar
);
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
log
(var global: typeof globalThisglobal.var myGlobalThisVar: string
커스텀 변수 설명
myGlobalThisVar
);
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
log
(module globalThisglobalThis.var myGlobalThisVar: string
커스텀 변수 설명
myGlobalThisVar
);
ts

현대 프레임워크

Vite의 경우 번들러 단에서 전역 객체 타입에 대한 지원을 제공합니다. declare global {} 없이 vite-env.d.ts에서 바로 타입을 명시하면 됩니다.
https://ko.vite.dev/guide/env-and-mode#intellisense-for-typescript

vite-env.d.ts
/// <reference types="vite/client" />

const myGlobalVar: string;

interface Window {
  myCustomVar: string;
}ts

반면 Next.js는 Webpack 기반이고, 프레임워크 단에서 별도 기능을 제공해주지 않기에 기존처럼 declare global {} 안에 타입을 명시해야 합니다.
https://nextjs.org/docs/app/api-reference/config/typescript#custom-type-declarations

맺으면서

전역 변수 타입 선언은 프로젝트의 유지보수성과 타입 안정성을 높이는 중요한 요소입니다. 사용법을 잘 확인하셔서 모두 Type-Safe한 코드를 작성했으면 좋겠습니다.