I have a TypeScript project with a file that loads env variables and export it:
const.ts:
const {
VARIABLE0, // type of VARIABLE0 is string | undefined
VARIABLE1,
} = process.env;
if (!VARIABLE0 || !VARIABLE1) {
throw new Error('Invalid env');
}
console.log(VARIABLE0); // type of VARIABLE0 is string
console.log(VARIABLE0.length);
export {
VARIABLE0, // type VARIABLE0 is string | undefined
VARIABLE1,
};
I don’t understand why the exported type is string | undefined
because before, I check that it is defined. On VS Code If I hover on VARIABLE0
after the check, it is string
but if I hover on the export, it is string | undefined
. It is anoying on other part of my code that uses this variables because I have to add ?
and !
in many places (for instance const length = VARIABLE0?.length!
instead of const length = VARIABLE0.length
).
Is there a way to export it as string
and not string | undefined
?
One way I see is:
const {
VARIABLE0: VARIABLE0_TEMP, VARIABLE1: VARIABLE1_TEMP,
} = process.env;
if (!VARIABLE0_TEMP || !VARIABLE1_TEMP) {
throw new Error('Invalid env');
}
const VARIABLE0 = <string>VARIABLE0_TEMP;
const VARIABLE1 = <string>VARIABLE1_TEMP;
export {
VARIABLE0, VARIABLE1,
};
But it’s probably not the best solution (it is quite verbose and I actually have around 10 variables to export like this).
>Solution :
One way to do it is to use an assertion function to narrow process.env
. For example:
function validateConfig<T extends string>(
env: NodeJS.ProcessEnv,
required: readonly T[], // readonly allows arg to be const-asserted
): asserts env is NodeJS.ProcessEnv & Record<T, string> {
const missing = required.filter((envVar) => !(envVar in env));
if (missing.length > 0) {
throw new Error(`missing required env vars: ${missing.join(", ")}`);
}
}
Now you can use this like:
validateConfig(process.env, [
"VARIABLE0",
"VARIABLE1",
]);
and either the error gets thrown or process.env.VARIABLE0
and process.env.VARIABLE1
are both string
, so you can then e.g.:
const { VARIABLE0, VARIABLE1 } = process.env;
export {
VARIABLE0, // type VARIABLE0 is string
VARIABLE1,
};
Note that if the required
argument is typed as string[]
the result will be NodeJS.ProcessEnv & Record<string, string>
, i.e. it tells the compiler that every possible environment variable will exist – either inline the list of required variables or type it as const
to get the narrower string union array/tuple type.