Wie man Umgebungsvariablen in TypeScript typisiert
Sie haben process.env.API_KEY zum hundertsten Mal geschrieben, und TypeScript typisiert es immer noch als string | undefined. Ihre IDE bietet keine Autovervollständigung. Schlimmer noch: Sie haben in die Produktion deployt, nur um festzustellen, dass eine fehlende Variable Ihre App zum Absturz gebracht hat. TypeScript-Umgebungsvariablen verdienen eine bessere Handhabung als diese.
Dieser Leitfaden zeigt Ihnen, wie Sie Typsicherheit für Umgebungsvariablen in modernen Frontend- und Full-Stack-Projekten hinzufügen – sowohl für import.meta.env in Vite-basierten Setups als auch für process.env in Node-Kontexten.
Wichtigste Erkenntnisse
- Browser-Apps verwenden Build-Time-Injection (Variablen werden in Bundles eingebacken), während Node.js Umgebungsvariablen zur Laufzeit liest – diese Unterscheidung beeinflusst sowohl Sicherheits- als auch Typisierungsstrategien.
- Verwenden Sie
ImportMetaEnv-Deklarationen für Vite-Projekte undNodeJS.ProcessEnv-Augmentation für Node-Kontexte, um IDE-Autovervollständigung und Type-Checking zu erhalten. - TypeScript-Typen allein können Laufzeit-Abstürze nicht verhindern – validieren Sie erforderliche Umgebungsvariablen immer beim Start mit einfachen Prüfungen oder Schema-Bibliotheken wie Zod.
- Legen Sie niemals Secrets in präfixierten Variablen (
VITE_,NEXT_PUBLIC_) ab, da diese in Client-seitigen Bundles sichtbar werden.
Build-Time- vs. Runtime-Umgebungsvariablen verstehen
Bevor Sie etwas typisieren, sollten Sie eine wichtige Unterscheidung verstehen: Browser-Apps und Server handhaben Umgebungsvariablen unterschiedlich.
Build-Time-Injection (Browser-Apps): Tools wie Vite ersetzen Umgebungsvariablen-Referenzen während des Builds durch tatsächliche Werte. Die Variablen existieren zur Laufzeit nicht – sie sind in Ihr JavaScript-Bundle eingebacken.
Runtime-Umgebungsvariablen (Server-seitig): Node.js liest process.env aus der tatsächlichen Systemumgebung, wenn Ihr Code ausgeführt wird. Werte können sich zwischen Deployments ändern, ohne dass ein Rebuild erforderlich ist.
Diese Unterscheidung ist wichtig für die Sicherheit. Jede Variable, die zur Build-Zeit injiziert wird, wird in Ihrem Client-seitigen Code sichtbar. Deshalb verwenden Frameworks präfix-basierte Offenlegungsregeln – Vite exponiert nur Variablen, die mit VITE_ beginnen, und Next.js exponiert Client-seitige Variablen mit dem Präfix NEXT_PUBLIC_. Private Keys ohne diese Präfixe bleiben nur Server-seitig.
Typisierung von import.meta.env in Vite-Projekten
Vite verwendet import.meta.env anstelle von process.env. Um typsichere Umgebungsvariablen in TypeScript hinzuzufügen, erstellen Sie eine Deklarationsdatei:
// env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string
readonly VITE_APP_TITLE: string
// add more variables here
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
Jetzt bietet TypeScript Autovervollständigung und behandelt diese als string statt string | undefined. Platzieren Sie diese Datei in Ihrem src-Verzeichnis und stellen Sie sicher, dass Ihre tsconfig.json sie einschließt.
Typisierung von ProcessEnv für Node.js-Kontexte
Für Server-seitigen Code oder Tools, die process.env verwenden, erweitern Sie das NodeJS.ProcessEnv-Interface:
// globals.d.ts
declare namespace NodeJS {
interface ProcessEnv {
DATABASE_URL: string
API_SECRET: string
NODE_ENV: 'development' | 'production' | 'test'
}
}
Dieser Ansatz gibt Ihnen Autovervollständigung in Ihrer gesamten Codebasis. Das NODE_ENV-Beispiel zeigt, dass Sie Union-Typen für Variablen mit bekannten möglichen Werten verwenden können.
Discover how at OpenReplay.com.
Warum Typen allein nicht ausreichen
Hier ist der Haken: Declaration Merging teilt TypeScript mit, was existieren sollte, nicht was tatsächlich existiert. Sie haben DATABASE_URL als string typisiert, aber wenn jemand vergisst, es zu setzen, stürzt Ihre App zur Laufzeit ab.
TypeScript-Typen werden zur Compile-Zeit gelöscht. Sie können nicht validieren, dass Umgebungsvariablen tatsächlich existieren, wenn Ihr Code läuft.
Validierung von Umgebungsvariablen beim Start
Um Umgebungsvariablen in TypeScript zu validieren, prüfen Sie sie früh – bevor Ihre App etwas Wichtiges tut. Ein einfacher Ansatz:
// 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
Importieren Sie dieses Config-Modul am Einstiegspunkt Ihrer App. Wenn eine Variable fehlt, erfahren Sie es sofort, anstatt es mitten in einer Anfrage zu entdecken.
Für robustere Validierung ermöglichen Bibliotheken wie Zod Ihnen, Schemas zu definieren, die Typen, Formate und Constraints validieren:
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)
Dies schlägt schnell mit klaren Fehlermeldungen fehl, wenn DATABASE_URL keine gültige URL ist oder PORT keine Zahl ist.
Ihre Variablen sicher halten
Denken Sie an die Präfix-Regeln. In Vite-Projekten erreichen nur Variablen mit dem Präfix VITE_ den Browser. Alles andere ist nur für den Build-Prozess (Server-seitig) verfügbar und wird nicht an den Browser ausgeliefert. Legen Sie niemals Secrets in präfixierten Variablen ab – sie werden in Ihrem Produktions-Bundle sichtbar sein.
Für Server-seitige Secrets verlassen Sie sich auf die Umgebungskonfiguration Ihrer Hosting-Plattform statt auf .env-Dateien in der Produktion. Fügen Sie .env sofort zu Ihrer .gitignore hinzu.
Fazit
Typsichere Umgebungsvariablen in TypeScript erfordern zwei Ebenen: Declaration Merging für Compile-Time-Autovervollständigung und Runtime-Validierung für Produktionssicherheit. Verwenden Sie ImportMetaEnv für Vite-Projekte, NodeJS.ProcessEnv für Node-Kontexte und validieren Sie immer erforderliche Variablen beim Start. Ihr zukünftiges Ich – beim Debuggen eines Produktionsvorfalls um 3 Uhr morgens – wird es Ihnen danken.
FAQs
Ja, aber halten Sie die Deklarationen getrennt. Erstellen Sie eine env.d.ts-Datei mit ImportMetaEnv für Ihre Vite-Frontend-Pakete und eine globals.d.ts mit NodeJS.ProcessEnv-Augmentation für Backend-Pakete. Die tsconfig.json jedes Pakets sollte nur die relevante Deklarationsdatei einschließen, um Typkonflikte zu vermeiden.
Ihre tsconfig.json schließt wahrscheinlich die Deklarationsdatei nicht ein. Prüfen Sie, ob Ihr include-Array den Dateispeicherort abdeckt, oder fügen Sie den Dateipfad explizit hinzu. Überprüfen Sie auch, ob Sie das Interface nicht versehentlich in einer anderen Deklarationsdatei überschatten. Starten Sie Ihren TypeScript-Server nach Änderungen neu.
Für Frontend-Apps ist die Validierung zur Build-Zeit nützlicher, da Variablen während des Build-Prozesses eingebacken werden. Fügen Sie ein prebuild-Script hinzu, das prüft, ob erforderliche VITE_-Variablen existieren, bevor Vite läuft. Runtime-Validierung im Browser kann sich ohnehin nicht von fehlenden Variablen erholen.
Markieren Sie optionale Variablen mit einem Fragezeichen in Ihrer Interface-Deklaration, wie OPTIONAL_VAR?: string. Für die Validierung verwenden Sie Zods optional()-Methode oder stellen Sie Standardwerte mit default() bereit. Ihr Config-Objekt sollte widerspiegeln, welche Variablen wirklich erforderlich sind versus nice-to-have.
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.