Typescript: strictNullChecks - property accesses on string index signatures should narrow

Created on 22 Aug 2017  ·  3Comments  ·  Source: microsoft/TypeScript



TypeScript Version: 2.6.0-dev.20170819

Code

// process.env is defined as { [key: string]: string | undefined } in @types/node

// Expected
console.log(process.env.MY_ENV_VAR.length);  // TS2532: Object is possibly 'undefined'

if (process.env.MY_ENV_VAR) {
  // Unexpected - process.env.MY_ENV_VAR is defined here
  console.log(process.env.MY_ENV_VAR.length); // TS2532: Object is possibly 'undefined'
}

/* ------------------------------------------------------------------------------------- */

const collection: { [id: string]: string } = {};

console.log(collection.someVar.length); // No error

Expected behavior:
When using strictNullChecks :

  • The compiler should not emmit an TS2532: Object is possibly 'undefined' error when accessing an index of an object defined as { [key: string]: string | undefined } inside a guard.
  • The compiler should emmit an error when accessing an index of an object defined as { [key: string]: string } inside a guard without checking it first.

Actual behavior:
Please see code sample.

Bug

Most helpful comment

It's also surprising that assigning the (theoretically) type narrowed object to a different variable removes the error:

if (process.env.MY_ENV_VAR) {
  console.log(process.env.MY_ENV_VAR.length); // ERROR
}

const v = process.env.MY_ENV_VAR;
if (v) {
  console.log(v.length); // NO ERROR
}

v is seemingly equivalent to process.env.MY_ENV_VAR; why do they behave differently?

All 3 comments

It's also surprising that assigning the (theoretically) type narrowed object to a different variable removes the error:

if (process.env.MY_ENV_VAR) {
  console.log(process.env.MY_ENV_VAR.length); // ERROR
}

const v = process.env.MY_ENV_VAR;
if (v) {
  console.log(v.length); // NO ERROR
}

v is seemingly equivalent to process.env.MY_ENV_VAR; why do they behave differently?

Another seemingly related error (TS 3.4.5):

declare const foo: {
    [id: string]: {
        bar?: {
            baz?: boolean;
        }
    }
};
const a1 = foo.id && foo.id.bar && foo.id.bar.baz; // works fine
const key = 'id';
const a2 = foo[key] && foo[key].bar && foo[key].bar.baz; // error: Object is possibly 'undefined'

playground

Was this page helpful?
0 / 5 - 0 ratings

Related issues

remojansen picture remojansen  ·  3Comments

fwanicka picture fwanicka  ·  3Comments

Antony-Jones picture Antony-Jones  ·  3Comments

manekinekko picture manekinekko  ·  3Comments

dlaberge picture dlaberge  ·  3Comments