TypeScript : enum, 매번 import 없이 전역으로 쓰는 법

JooSehyun·2025년 4월 8일
0

[Study]

목록 보기
58/59
post-thumbnail

Global enum 열거 타입 사용

기존 프로젝트의 전역으로 사용할 타입을 global 폴더 내부에 declare global로 지정하고 .eslintrc 에서 import 없이 전역으로 사용했다.


📄global.d.ts

declare global {
	...
	enum UserRole {
        STD = 'S'
        TCH = 'T'
    }
	...
}

📄.eslintrc

"globals": {
		...
        "UserRole": "readonly",
        "Answer": "readonly",
		...
},

Error

🔴 Uncaught (in promise) ReferenceError: UserRole is not defined


문제는 enum 열거 타입은 전역으로 사용이 되지 않았다. 위와 같이 에러가 뜬다.

TypeScript에서 declare global로만 enum을 정의했을 때, 그리고 런타임에서 그 enum을 객체처럼 접근하려고 할 때 발생한다고 한다.

이렇게 하면 TS 타입 시스템 상에서는 UserRole 존재하니까 자동완성도 되고, 오류도 안 난다.

하지만...


실제 런타임에서는

TypeScript는 declare된 enum은 JS 코드로 변환하지 않는다.

console.log(UserRole.STD); // ReferenceError

브라우저는 "UserRole이라는 변수는 정의돼 있지 않다" 고 말한다.

선언 방식타입 인식런타입 객체 존재import 없이 사용결과
declare enum
const enum (.ts 파일)❌ (문자열로 인라인됨)
export enum❌ (import 필요)

내가 원하는건 enum 열거형 타입으로 매개변수로 하드코딩으로 'T' 나 'S' 를 사용하는 것이 아닌 enum으로 상수값을 싱글톤처럼 관리 하고싶었다.


import 없이 전역(Global)에서 enum을 안전하게 쓰는 방법

  1. 공통 폴더에 user-role.enum.ts 파일을 생성 후 열거형 타입을 만든다.

📂 /src/type/common/user-role.enum.ts

export enum UserRole {
	STD = 'S',
	TCH = 'T',
}
  1. 글로벌 폴더에 global-enums.ts 파일을 생성 후 런타임 등록 스크립트를 작성한다.

📂 /src/type/global/global-enums.ts

import { UserRole } from '@/type/common/user-role.enum';

// 전역 객체에 붙여줌
(globalThis as any).UserRole = UserRole;
  1. 해당 global-enums.ts 의 파일을 최상위 main.ts 또는 진입점 파일에서 import한다.

📂 /src/main.ts

import '@/type/global/global-enums';
  1. (선택적) 타입 보장을 위한 글로벌 선언도 추가한다.
    📂 /src/type/global/global.d.ts
declare global {
	const UserRole: typeof import('@/type/common/user-role.enum').UserRole;

	...
	...
	...
}

export {};

결과

import 안 해도, 타입 추론 잘 됨

console.log(UserRole.TCH); // "T"

번외

가끔 UserRole 과 해당 유저 타입에 따른 쿠키 값 ex : T or S 이 있는데 조건문을 만들면 너무 길어지기도 하고 가독성이 떨어져 바로 boolean 값으로 나오게 하는 방법을 모색했는데, 이런 방법이 있어 작성해보게 되었다.

// account.util.ts
const userType: UserType = toCookie('userType') as UserType;

const _getUserType = (): UserType => {
    if (matchesProfile('LOCAL')) {
        return LOCAL_USER_TYPE;
    }
    return userType;

};

// App.vue
const userType = getUserType();

userType === UserRole.TCH;

🕵️ proxy 기반 enum 객체 만들기

// user-type-proxy.ts
const userTypeValue = {
	Teacher: 'T',
	Student: 'S',
};

export const UserType = new Proxy(userTypeValue, {
	get(target, prop: keyof typeof userTypeValue) {
		return cookie.get('userType') === target[prop];
	},
});

쿠키 안의 값과 비교해서 true/false 반환하게 만들어서

if (UserType.Teacher) {
	// 자동으로 쿠키에서 'T' 비교해줌
}

위와 같이 사용할 수도 있다.

🌟 장점

장점설명
🟢코드 가독성if (UserRole.TCH) 직관적, 간결
🟢쿠키 값 비교를 추상화로직 중복 제거, 어디서든 일관됨
🟢의미적 표현력로직이 의미 단위로 구성됨
🟢enum-like 사용UserRole.TCH , UserRole.SDT 가능

🚫단점

단점설명
🔴자동완성, 타입추론 약함TS에서는 UserRole.TCH 가 boolean으로 추론되지 않음
🔴예상치 못한 사이드 이펙트단순 접근인데 내부에서 cookie.get()이 실행됨, 순수하지 않은 접근자
🔴테스트 어려움테스트 시 쿠키 상태 mocking 필요
🔴추론 어려움협업 시 프록시 동작을 모르면 이해 안 되는 코드

개선 가능 포인트 예제

1. enum 값은 따로 유지

// user-type.enum.ts
export const UserTypeValue = {
	Teacher: 'T',
	Student: 'S',
} as const;

export type UserType = typeof UserTypeValue[keyof typeof UserTypeValue];

2. 프록시 유틸은 따로 구성

// user-type-proxy.ts
import { UserTypeValue } from './user-type.enum';
import { cookie } from '@/utils/cookie.util'; // 예시

export const isUserType = new Proxy(UserTypeValue, {
	get(target, prop: keyof typeof UserTypeValue) {
		return cookie.get('userType') === target[prop];
	},
});

3.사용

if (isUserType.Teacher) {
	// 간결함 + 의미적 명확성 유지
}

0개의 댓글