typescript narrow type on throw

I have this code here
const SALT_ROUNDS = process.env.SALT_ROUNDS;

if (!SALT_ROUNDS) throw new Error("salt rounds not specified for bcrypt");

export { SALT_ROUNDS}
const SALT_ROUNDS = process.env.SALT_ROUNDS;

if (!SALT_ROUNDS) throw new Error("salt rounds not specified for bcrypt");

export { SALT_ROUNDS}
but it doesn't narrow salt rounds type for export.
function assertTruthy (
param: unknown,
envName: string
): asserts param is string {
if (!param) throw new Error(`${envName} is not provided`);
else return;
}

assertTruthy(SALT_ROUNDS, "SALT_ROUNDS");
function assertTruthy (
param: unknown,
envName: string
): asserts param is string {
if (!param) throw new Error(`${envName} is not provided`);
else return;
}

assertTruthy(SALT_ROUNDS, "SALT_ROUNDS");
I tried this but it also doesn't work. Do i have to reassign a value or is there another way
22 Replies
Ganesh
GaneshOP3mo ago
ignore the asseerts param is string. I'm just trying to get something working for now
ἔρως
ἔρως3mo ago
process.env.SALT_ROUNDS <-- isn't the type of this set to any by default? if you want a string, just try something like this:
const SALT_ROUNDS = (process.env.SALT_ROUNDS ?? '').toString();
const SALT_ROUNDS = (process.env.SALT_ROUNDS ?? '').toString();
-------- maybe something like this could work too - I DO NOT KNOW IF THIS WORKS OR NOT!!!!:
export { SALT_ROUNDS as string }
export { SALT_ROUNDS as string }
Ganesh
GaneshOP3mo ago
the as syntax won't work. That jus works like an alias similar to the import statement counterpart yeah I guess I'll have to do this one. Annoying but works
ἔρως
ἔρως3mo ago
i expected it to do not work, but wasn't sure it is annoying you can use jsdoc just do /** @type {string|undefined} */ that should work
Ganesh
GaneshOP3mo ago
that's actually already the type of env vars on process.env
Ganesh
GaneshOP3mo ago
No description
ἔρως
ἔρως3mo ago
then you have to do the first one, to make sure it is a string yeah, that's not a good idea i don't think that the number constructor accepts undefined
Ganesh
GaneshOP3mo ago
it gives out NaN which throws error when doing !SALT_ROUNDS tho yes I should do 0 with your ??
ἔρως
ἔρως3mo ago
you should do '0'
Ganesh
GaneshOP3mo ago
/**
* This function checks if the given enviroment variable is empty string, '0' or falsy.
* If it is falsy an error will be thrown with message specifying enviroment variable's name
* @param envVar the enviroment variable to check
* @param envVarName name of enviroment variable
*/
function assertEnvVar(envVar: string | number, envVarName: string) {
if (envVar === "" || envVar === 0 || !envVar)
throw new Error(`${envVarName} enviroment varibale not provided`);
}

const SALT_ROUNDS = Number(process.env.SALT_ROUNDS ?? "0");
const JWT_SECRET = process.env.JWT_SECRET ?? "";
assertEnvVar(SALT_ROUNDS, "SALT_ROUNDS");
assertEnvVar(JWT_SECRET, "JWT_SECRET");

export { DATABASE_URL, SALT_ROUNDS, JWT_SECRET, SECRET_PASSWORD };
/**
* This function checks if the given enviroment variable is empty string, '0' or falsy.
* If it is falsy an error will be thrown with message specifying enviroment variable's name
* @param envVar the enviroment variable to check
* @param envVarName name of enviroment variable
*/
function assertEnvVar(envVar: string | number, envVarName: string) {
if (envVar === "" || envVar === 0 || !envVar)
throw new Error(`${envVarName} enviroment varibale not provided`);
}

const SALT_ROUNDS = Number(process.env.SALT_ROUNDS ?? "0");
const JWT_SECRET = process.env.JWT_SECRET ?? "";
assertEnvVar(SALT_ROUNDS, "SALT_ROUNDS");
assertEnvVar(JWT_SECRET, "JWT_SECRET");

export { DATABASE_URL, SALT_ROUNDS, JWT_SECRET, SECRET_PASSWORD };
how about this
ἔρως
ἔρως3mo ago
it's missing the types for the parameters in the jsdoc, even if it is redundant
Ganesh
GaneshOP3mo ago
why add them if they are redundant though? jsDoc with typescript mainly seems to be for doc intellisense while typescript handles the types
ἔρως
ἔρως3mo ago
🤔 it was the first thing i noticed but why are you asserting the environment var by throwing an error?
Ganesh
GaneshOP3mo ago
I want the whole app to crash if environment var is not present/undefined. It should not work at all
ἔρως
ἔρως3mo ago
the number one will fail if it converts to NaN
Ganesh
GaneshOP3mo ago
ah dammit true
function assertEnvVar(envVar: string | number, envVarName: string) {
if (envVar === "" || envVar === 0 || Number.isNaN(envVar) || !envVar)
throw new Error(`${envVarName} enviroment varibale not provided`);
}
function assertEnvVar(envVar: string | number, envVarName: string) {
if (envVar === "" || envVar === 0 || Number.isNaN(envVar) || !envVar)
throw new Error(`${envVarName} enviroment varibale not provided`);
}
maybe i should remove the 0 and "" condition since !envVar takes care of that but I like to be explicit
function assertEnvVar(envVar: string | number, envVarName: string) {
const errMessage = `${envVarName} enviroment varibale not provided`;
if (typeof envVar === "string" && envVar.trim() === "")
throw new Error(errMessage);
else if (envVar === 0 || Number.isNaN(envVar)) throw new Error(errMessage);
else if (!envVar) throw new Error(errMessage);
}
function assertEnvVar(envVar: string | number, envVarName: string) {
const errMessage = `${envVarName} enviroment varibale not provided`;
if (typeof envVar === "string" && envVar.trim() === "")
throw new Error(errMessage);
else if (envVar === 0 || Number.isNaN(envVar)) throw new Error(errMessage);
else if (!envVar) throw new Error(errMessage);
}
this should take care of everything and is more readable
Rägnar O'ock
Rägnar O'ock3mo ago
What exactly are you trying to do?
Ganesh
GaneshOP3mo ago
well in the beginning I was trying to assert that env vars are of string type by throwing errors if they were undefined
Rägnar O'ock
Rägnar O'ock3mo ago
Let me rephrase, why are you trying to do that? What is the end goal
Ganesh
GaneshOP3mo ago
the app should not work if the env variable is undefined but throwing errors will not narrow the type. so i had to assign empty string or 0 (in case of salt rounds) to narrow the type to string or number. Then the above function checks if the env var is empty string 0, NaN or falsy then throws throwing errors is simply for my convenience as it will inform me if i forgot to set an environment variable
Rägnar O'ock
Rägnar O'ock3mo ago
what you posted should work, but in general it's better to check the validity of the inputs where they are used, that way you can provide more contextual error message. 'cause right now you would get something like Error: SALT_ROUND enviroment varibale not provided but you would not know what it does, why it's needed or even what the value should be
Ganesh
GaneshOP3mo ago
I do have an env.example file to explain the purpose of all environment variables. I guess I'll do it where it should be

Did you find this page helpful?