Back

Cómo Tipar Variables de Entorno en TypeScript

Cómo Tipar Variables de Entorno en TypeScript

Has escrito process.env.API_KEY por centésima vez, y TypeScript todavía lo tipa como string | undefined. Tu IDE no ofrece autocompletado. Peor aún, desplegaste a producción solo para descubrir que una variable faltante hizo que tu aplicación fallara. Las variables de entorno en TypeScript merecen un mejor manejo que esto.

Esta guía te muestra cómo agregar seguridad de tipos a las variables de entorno en proyectos modernos de frontend y full-stack—cubriendo tanto import.meta.env para configuraciones basadas en Vite como process.env para contextos de Node.

Puntos Clave

  • Las aplicaciones de navegador usan inyección en tiempo de compilación (variables integradas en los bundles), mientras que Node.js lee las variables de entorno en tiempo de ejecución—esta distinción afecta tanto las estrategias de seguridad como de tipado.
  • Usa declaraciones ImportMetaEnv para proyectos Vite y aumentación de NodeJS.ProcessEnv para contextos de Node para obtener autocompletado del IDE y verificación de tipos.
  • Los tipos de TypeScript por sí solos no pueden prevenir fallos en tiempo de ejecución—siempre valida las variables de entorno requeridas al inicio usando verificaciones simples o librerías de esquemas como Zod.
  • Nunca pongas secretos en variables con prefijo (VITE_, NEXT_PUBLIC_) ya que estas se vuelven visibles en los bundles del lado del cliente.

Entendiendo Variables de Entorno en Tiempo de Compilación vs. Tiempo de Ejecución

Antes de tipar cualquier cosa, entiende una distinción crítica: las aplicaciones de navegador y los servidores manejan las variables de entorno de manera diferente.

Inyección en tiempo de compilación (aplicaciones de navegador): Herramientas como Vite reemplazan las referencias a variables de entorno con valores reales durante la compilación. Las variables no existen en tiempo de ejecución—están integradas en tu bundle de JavaScript.

Variables de entorno en tiempo de ejecución (lado del servidor): Node.js lee process.env del entorno real del sistema cuando tu código se ejecuta. Los valores pueden cambiar entre despliegues sin necesidad de recompilar.

Esta distinción importa para la seguridad. Cualquier variable inyectada en tiempo de compilación se vuelve visible en tu código del lado del cliente. Por eso los frameworks usan reglas de exposición basadas en prefijos—Vite solo expone variables que comienzan con VITE_, y Next.js expone variables del lado del cliente con el prefijo NEXT_PUBLIC_. Las claves privadas sin estos prefijos permanecen solo del lado del servidor.

Tipando import.meta.env en Proyectos Vite

Vite usa import.meta.env en lugar de process.env. Para agregar variables de entorno con seguridad de tipos en TypeScript, crea un archivo de declaración:

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

interface ImportMetaEnv {
  readonly VITE_API_URL: string
  readonly VITE_APP_TITLE: string
  // agrega más variables aquí
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}

Ahora TypeScript proporciona autocompletado y trata estas como string en lugar de string | undefined. Coloca este archivo en tu directorio src y asegúrate de que tu tsconfig.json lo incluya.

Tipando ProcessEnv para Contextos de Node.js

Para código del lado del servidor o herramientas que usan process.env, aumenta la interfaz NodeJS.ProcessEnv:

// globals.d.ts
declare namespace NodeJS {
  interface ProcessEnv {
    DATABASE_URL: string
    API_SECRET: string
    NODE_ENV: 'development' | 'production' | 'test'
  }
}

Este enfoque te da autocompletado en todo tu código base. El ejemplo de NODE_ENV muestra que puedes usar tipos de unión para variables con valores posibles conocidos.

Por Qué los Tipos Solos No Son Suficientes

Aquí está el problema: la fusión de declaraciones le dice a TypeScript lo que debería existir, no lo que existe. Has tipado DATABASE_URL como string, pero si alguien olvida configurarla, tu aplicación falla en tiempo de ejecución.

Los tipos de TypeScript se eliminan en tiempo de compilación. No pueden validar que las variables de entorno realmente existan cuando tu código se ejecuta.

Validando Variables de Entorno al Inicio

Para validar variables de entorno en TypeScript, veríficalas temprano—antes de que tu aplicación haga algo importante. Un enfoque simple:

// config.ts
function getEnvVar(key: string): string {
  const value = process.env[key]
  if (!value) {
    throw new Error(`Missing required environment variable: ${key}`)
  }
  return value
}

export const config = {
  databaseUrl: getEnvVar('DATABASE_URL'),
  apiSecret: getEnvVar('API_SECRET'),
} as const

Importa este módulo de configuración en el punto de entrada de tu aplicación. Si falta alguna variable, lo sabrás inmediatamente en lugar de descubrirlo a mitad de una petición.

Para una validación más robusta, librerías como Zod te permiten definir esquemas que validan tipos, formatos y restricciones:

import { z } from 'zod'

const envSchema = z.object({
  DATABASE_URL: z.string().url(),
  PORT: z.string().transform(Number).pipe(z.number().min(1)),
})

export const env = envSchema.parse(process.env)

Esto falla rápidamente con mensajes de error claros si DATABASE_URL no es una URL válida o PORT no es un número.

Manteniendo Tus Variables Seguras

Recuerda las reglas de prefijos. En proyectos Vite, solo las variables con prefijo VITE_ llegan al navegador. Todo lo demás solo está disponible para el proceso de compilación (lado del servidor) y no se envía al navegador. Nunca pongas secretos en variables con prefijo—serán visibles en tu bundle de producción.

Para secretos del lado del servidor, confía en la configuración de entorno de tu plataforma de hosting en lugar de archivos .env en producción. Agrega .env a tu .gitignore inmediatamente.

Conclusión

Las variables de entorno con seguridad de tipos en TypeScript requieren dos capas: fusión de declaraciones para autocompletado en tiempo de compilación y validación en tiempo de ejecución para seguridad en producción. Usa ImportMetaEnv para proyectos Vite, NodeJS.ProcessEnv para contextos de Node, y siempre valida las variables requeridas al inicio. Tu yo futuro—depurando un incidente de producción a las 3 AM—te lo agradecerá.

Preguntas Frecuentes

Sí, pero mantén las declaraciones separadas. Crea un archivo env.d.ts con ImportMetaEnv para tus paquetes frontend de Vite y un globals.d.ts con aumentación de NodeJS.ProcessEnv para paquetes backend. El tsconfig.json de cada paquete solo debe incluir su archivo de declaración relevante para evitar conflictos de tipos.

Tu tsconfig.json probablemente no está incluyendo el archivo de declaración. Verifica que tu array include cubra la ubicación del archivo, o agrega la ruta del archivo explícitamente. También verifica que no estés sombreando accidentalmente la interfaz en otro archivo de declaración. Reinicia tu servidor de TypeScript después de hacer cambios.

Para aplicaciones frontend, la validación en tiempo de compilación es más útil ya que las variables se integran durante el proceso de compilación. Agrega un script prebuild que verifique que las variables VITE_ requeridas existan antes de que Vite se ejecute. La validación en tiempo de ejecución en el navegador no puede recuperarse de variables faltantes de todos modos.

Marca las variables opcionales con un signo de interrogación en tu declaración de interfaz, como OPTIONAL_VAR?: string. Para validación, usa el método optional() de Zod o proporciona valores predeterminados con default(). Tu objeto de configuración debe reflejar qué variables son verdaderamente requeridas versus deseables.

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay