Flow: process.env type checking bug

Created on 17 Jul 2019  路  8Comments  路  Source: facebook/flow

Flow version: 0.102.0

Expected behavior

I would like to be able to check process.env variables with if blocks like in #1192.

Actual behavior

The if block has to be placed right before using the process.env variable.

I cannot reproduce in Flow Try cause it does not support process.env. Here is the code:

Working example:

if (!process.env.environment) throw new Error('dbHost missing');

// Get the password secret for the database
const dbSecret = await getDBSecret(process.env.environment)

if (!process.env.dbHost) throw new Error('dbHost missing');
if (!process.env.dbUser) throw new Error('dbUser missing');
if (!process.env.dbName) throw new Error('dbName missing');

// Connect to database and return handle
this.handle = knex({
  client: 'mysql',
  connection: {
    host: process.env.dbHost,
    user: process.env.dbUser,
    password: dbSecret,
    database: process.env.dbName,
  },
})

Breaking example:

if (!process.env.environment) throw new Error('dbHost missing');
if (!process.env.dbHost) throw new Error('dbHost missing');
if (!process.env.dbUser) throw new Error('dbUser missing');
if (!process.env.dbName) throw new Error('dbName missing');

// Get the password secret for the database
const dbSecret = await getDBSecret(process.env.environment)

// Connect to database and return handle
this.handle = knex({
  client: 'mysql',
  connection: {
    host: process.env.dbHost,
    user: process.env.dbUser,
    password: dbSecret,
    database: process.env.dbName,
  },
})

Produces the following error:

Cannot call `knex` with object literal bound to `config` because  null or undefined [1] is incompatible with  string [2] in property `connection.host`.

because Flow do not see that I check the variable anymore if there is another instruction between the checks and the usage.

This is not a blocking bug, it's only preferable for code quality to do all the checks first before actually running the code. And we cannot because of this issue.

Thanks in advance.

bug needs triage

Most helpful comment

You just need to use constants:

const {
  environment,
  dbHost,
  dbUser,
  dbName,
} = process.env;
if (!environment) throw new Error('dbHost missing');
if (!dbHost) throw new Error('dbHost missing');
if (!dbUser) throw new Error('dbUser missing');
if (!dbName) throw new Error('dbName missing');

// Get the password secret for the database
const dbSecret = await getDBSecret(environment)

// Connect to database and return handle
this.handle = knex({
  client: 'mysql',
  connection: {
    host: dbHost,
    user: dbUser,
    password: dbSecret,
    database: dbName,
  },
})

All 8 comments

This is limit of refinements, they're invalidated if you're calling functions between them

Why tho ? Calling a function between them will not make it bug .. just makes it cleaner

You can mutate it between calls

var obj = { prop: "test" };

function otherMethod() {
  if (Math.random() > 0.5) {
    delete obj.prop;
  }
}

I call this an anti-pattern.

anyway thanks for your answer

You just need to use constants:

const {
  environment,
  dbHost,
  dbUser,
  dbName,
} = process.env;
if (!environment) throw new Error('dbHost missing');
if (!dbHost) throw new Error('dbHost missing');
if (!dbUser) throw new Error('dbUser missing');
if (!dbName) throw new Error('dbName missing');

// Get the password secret for the database
const dbSecret = await getDBSecret(environment)

// Connect to database and return handle
this.handle = knex({
  client: 'mysql',
  connection: {
    host: dbHost,
    user: dbUser,
    password: dbSecret,
    database: dbName,
  },
})

thanks for this great solution @jcready !

Was this page helpful?
0 / 5 - 0 ratings