기존 프로젝트의 전역으로 사용할 타입을 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으로 상수값을 싱글톤처럼 관리 하고싶었다.
user-role.enum.ts
파일을 생성 후 열거형 타입을 만든다.📂 /src/type/common/user-role.enum.ts
export enum UserRole {
STD = 'S',
TCH = 'T',
}
global-enums.ts
파일을 생성 후 런타임 등록 스크립트를 작성한다.📂 /src/type/global/global-enums.ts
import { UserRole } from '@/type/common/user-role.enum';
// 전역 객체에 붙여줌
(globalThis as any).UserRole = UserRole;
global-enums.ts
의 파일을 최상위 main.ts
또는 진입점 파일에서 import
한다.📂 /src/main.ts
import '@/type/global/global-enums';
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;
// 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) {
// 간결함 + 의미적 명확성 유지
}