TypeScript 프로젝트에서 환경 설정을 타입 안전하게 관리하는 방법을 정리한 글이다. `config` 모듈을 쓰다 오타 때문에 운영에서 잘못된 설정이 적용되는 사고가 반복되자, 외부 모듈 없이 설정 파일 자체를 TypeScript 로 두어 타입 정의로 삼는 방식을 만들었다.
핵심 포인트- 설정을 코드에서 분리하는 이유는 두 가지다. 암호·접근키를 코드에 두지 않기 위해서, 그리고 개발·운영·테스트마다 다른 값을 쓰기 위해서다.
- 크로키닷컴은 첫 번째 이슈가 크지 않았다. 환경 변수 설정도 번거로워 AWS Instance Role 이나 Parameter Store 로 우회하고 있었다.
- 문제는 `config` 모듈이 오타를 잡아 주지 않아 개발에서는 되는데 운영에서 잘못된 설정이 먹히는 실수가 종종 났다는 점이다.
- 해결은 설정 파일을 JSON 이 아니라 TypeScript 로 두는 것이다. `config/default.ts` 가 곧 타입 정의가 되고 다른 코드는 그 타입으로 검사받는다.
- 환경별 파일은 달라지는 부분만 정의하고 `config/index.ts` 에서 `NODE_ENV` 에 따라 병합해 내보낸다.
상세 정리- 기존 대안들의 위치를 먼저 정리한다. 환경 변수를 쓰려면 프로세스 구동마다 설정하는 게 번거로워 `dotenv` 같은 모듈을 쓰고, 환경별 값이 필요하면 `config` 모듈을 쓴다.
- 타입 있는 설정 모듈(`ts-config` 계열)도 찾아봤지만 원하는 형태와 거리가 있었다.
- 전환이 쉬웠던 배경: 애초에 설정 파일을 JSON 이 아니라 JavaScript 로 관리하고 있었기에 그대로 TypeScript 로 옮기면 그 자체가 타입 정의가 된다는 발상이었다.
- 구조: `config/default.ts` 에 기본 구조를 정의하고, `config/test.ts` 처럼 환경별 파일에는 달라지는 값만 쓴다. `config/index.ts` 가 이를 묶어 다른 코드에 제공한다.
- 남는 문제: 이대로면 `test.ts` 에서 `test_mode` 를 `testmode` 로 잘못 쓰거나 타입이 어긋나도 알려주지 않는다.
- 보완: `default.ts` 에 타입 제약을 추가하고 `test.ts` 를 그에 맞게 고치면, port 를 string 과 number 로 다르게 쓴 경우 컴파일 오류가 난다.
- 한계 ①: 병합에 lodash 의 merge 를 쓰기 때문에 default 에서 정의한 값을 `undefined` 로 덮어쓸 수 없다.
- 한계 ②: default 설정의 타입이 기준이 되므로 환경마다 설정 형태가 크게 다르면 default 쪽에 타입을 명시적으로 써 줘야 할 수 있다.
왜 읽나설정 오타 때문에 운영에서 사고를 낸 적 있는 Node.js·TypeScript 개발자에게 외부 모듈 없이 타입 검사를 붙이는 최소 구조를 준다.