✓ เสร็จแล้ว
type-safe-env
TypeScript utility สำหรับ parse และ validate environment variables ด้วย Zod — crash ทันทีถ้า env ขาดหาย แทนที่จะ fail แบบ silent
สารบัญ
ภาพรวม
ปัญหาที่พบบ่อย: application รันไปได้สักพักแล้วค่อย crash ด้วย Cannot read properties of undefined เพราะ process.env.SOME_KEY เป็น undefined โดยไม่รู้ตัวตั้งแต่ start
โปรเจกต์นี้เป็น utility ที่รับ Zod schema แล้ว parse process.env ตั้งแต่ต้น — ถ้าขาด key หรือ type ผิด จะ throw ทันทีพร้อม error message บอกว่าขาด variable อะไร
วิธีใช้งาน
// env.ts
import { parseEnv } from './type-safe-env';
import { z } from 'zod';
export const env = parseEnv(
z.object({
NODE_ENV: z.enum(['development', 'production', 'test']),
PORT: z.coerce.number().int().min(1).max(65535).default(3000),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
})
);
// type-safe ทันที:
env.PORT // number
env.NODE_ENV // 'development' | 'production' | 'test'
env.DATABASE_URL // string
ถ้า DATABASE_URL ขาดหาย:
Error: Environment variable validation failed:
DATABASE_URL: Required
JWT_SECRET: String must contain at least 32 character(s)
สิ่งที่ทำ
- รับ Zod schema แล้ว parse
process.envทั้งหมด - collect errors ทุกตัวก่อน throw ครั้งเดียว (ไม่ throw ทีละตัว)
- รองรับ
.default()ใน schema - รองรับ
z.coerce.number()สำหรับ PORT, TIMEOUT, etc. - export type ของผลลัพธ์อัตโนมัติจาก schema
ปัญหาที่เจอ
Zod z.coerce ทำงานก่อน parse ดังนั้น z.coerce.number().min(1) จะ coerce 'abc' เป็น NaN ก่อน แล้วค่อย fail ที่ .min(1) — error message จึงออกมาเป็น “Number must be greater than or equal to 1” ไม่ใช่ “Invalid number” จัดการโดยเพิ่ม custom message ใน .coerce.number({ invalid_type_error: 'Must be a number' })
เทคโนโลยี
- TypeScript 5
- Zod 3
- Node.js 20+