TypeScript Patterns for Environment Variables A developer discovered that TypeScript's type inference does not narrow types after using .filter(Boolean) on an array containing undefined values, leaving the type as (string | undefined)[] despite runtime correctness. The developer explains that using a type predicate like .filter((origin): origin is string => Boolean(origin)) or a utility function isDefined correctly narrows the type to string[]. The post highlights the gap between runtime behavior and TypeScript's static analysis. Yesterday, as I was working on a CORS configuration, AI generated a block of code for me: js const allowedOrigins = process.env.FRONTEND URL || "http://localhost:3000", process.env.ADMIN URL || "http://localhost:3001", .filter Boolean ; I was wondering... why use .filter Boolean here? 🤔 The fallbacks already guarantee strings. So I hovered on the variable. The type definition read: js const allowedOrigins: string Fine. Made sense. But then I got curious. What if I removed the hardcoded fallbacks? js const allowedOrigins = process.env.FRONTEND URL, process.env.ADMIN URL, .filter Boolean ; My type definition changed to: js const allowedOrigins: string | undefined I was shocked. I just filtered the array. How can TypeScript still think there's an undefined in there? .filter Boolean Even Do? Boolean used as a filter function removes any falsy value from an array: false null undefined 0 "" NaN So: "https://app.com", "", undefined .filter Boolean // Result: "https://app.com" At runtime, this works exactly as you'd expect. No undefined survives. So why does TypeScript disagree? 🤷♀️ TypeScript is a transpiler. It doesn't execute .filter Boolean — it only looks at types. When it sees this: array.filter Boolean It knows the callback returns a boolean . But it doesn't know what that means for the type of the elements that survive. It can't infer "if Boolean x is true, then x must be a string." So the undefined stays in the type — even though it'll never actually be there at runtime. That's the gap: your runtime behavior is correct, but your types are lying. TypeScript lets you close that gap with a type predicate — a way of explicitly telling the compiler what a filter function guarantees: js const allowedOrigins = process.env.FRONTEND URL, process.env.ADMIN URL, .filter origin : origin is string = Boolean origin ; // Type: string ✅ The origin is string part is the predicate. It's a promise to the compiler: "if this function returns true, the value is definitely a string." TypeScript trusts that and narrows the type accordingly. If you're doing this pattern often across a codebase, pull it into a small utility: function isDefined