Not a direct answer to the question, but if you're using TypeScript I've found runtypes to be a great alternative to manually validating and throwing. While the approach in the OP works when the input type is output | null | undefined
or something similar, runtypes also works when the input type is any
, such as when defensively decoding a JSON with a known structure.
You would use it like so:
import { String } from 'runtypes';
const setting = String.check(process.env.SETTING)
It'll throw if process.env.SETTING
is undefined
. Add .withConstraint()
to add other conditions. The library is actually quite powerful and can validate not only simple types but records (interfaces), unions, etc. in a type-safe way.
One drawback is that you don't get to customize the error message ("Failed constraint check"), which is OK in a lot of fast-and-dirty cases because the line the error occurred will tell you what the problem was.
io-ts is another similar library, though it seems to have a more complicated approach and is in flux at the moment.