Typescript: strictNullChecks mode - Object is possibly 'undefined'.

Created on 31 Aug 2016  路  7Comments  路  Source: microsoft/TypeScript

In strictNullChecks mode only:

TypeScript Version: nightly (2.0.2)

Code

interface IRoute {
  children?: IRoute[];
}

function register(route: IRoute) {
  if (route.children) {                                   // <-- route.children is of type IRoute|undefined
    Object.keys(route.children).forEach(routeKey => {     // <-- route.children is of type IRoute
      register(route.children[routeKey]);  // <-- Error: Object 'route.children' is possibly 'undefined'.
    });
  }
}

Expected behavior:

There shouldn't be an error here, because route.children is being checked 2 lines above.

Actual behavior:

TypeScript fails to recognize route.children cannot be undefined anymore, because of the nested function. It is the same behavior with both function declaration and arrow functions.

Working as Intended

Most helpful comment

This is the intended behavior because we don't know that route.children is _still_ not-undefined at the point when the callback executes. It is the case that forEach executes its callback immediately, but this is not true of all functions and we don't know that someone isn't going to remove route.children after you leave the scope of register.

A good solution is to capture the property in a const, which we can statically know will still be not-undefined

function register(route: IRoute) {
  const children = route.children;
  if (children) {                                   // <-- children is of type IRoute|undefined
    Object.keys(children).forEach(routeKey => {     // <-- children is of type IRoute
      register(children[routeKey]);  // <-- OK
    });
  }
}

All 7 comments

This is the intended behavior because we don't know that route.children is _still_ not-undefined at the point when the callback executes. It is the case that forEach executes its callback immediately, but this is not true of all functions and we don't know that someone isn't going to remove route.children after you leave the scope of register.

A good solution is to capture the property in a const, which we can statically know will still be not-undefined

function register(route: IRoute) {
  const children = route.children;
  if (children) {                                   // <-- children is of type IRoute|undefined
    Object.keys(children).forEach(routeKey => {     // <-- children is of type IRoute
      register(children[routeKey]);  // <-- OK
    });
  }
}

Thanks @RyanCavanaugh for the fast feedback :) That's true! I never thought of that possibility.

I just enabled strictNullChecks for our project and found these 3 issues (2 I posted earlier) that I couldn't wrap my head around. Truly amazing work :+1:

@RyanCavanaugh for some reason this is not working for 2.0.10 and 2.1+ for me right now.

There got to be something on my side as it was working....

  let deferred = defer()
  setTimeout(() => {
    if (deferred) {
      deferred.resolve(1) // <-- still error with Object is possibly 'undefined'
    }
  }, 1)

Need some help. 馃檱

@unional please post question on Stack Overflow and/or provide a self-contained example

Yes. I can reproduce it:

// index.ts
export function defer() {
  let resolve
  let reject
  let promise = new Promise((r, j) => {
    resolve = r;
    reject = j;
  });
  return {
    resolve: resolve,
    reject: reject,
    promise: promise
  };
}

let deferred = defer()
setTimeout(() => {
  if (deferred !== undefined) {
    deferred.reject(1)  // <-- in VSC there is no error, but compiles fail
  }
}, 1)
// tsconfig.json
{
  "compilerOptions": {
    "lib": [
      "es2015",
      "dom"
    ],
    "strictNullChecks": true,
    "target": "es5"
  },
  "include": [
    "index.ts"
  ]
}

error:

index.ts(18,5): error TS2532: Object is possibly 'undefined'.

Tested with [email protected]

And it turns out the issue is fixed in [email protected] and does not exist in 2.0.10

Have the same issue with typescript (tsc) version 2.3.4
with the process module.

process.on('message', (msg) => {
  console.log('Message from parent:', msg);
});

but doing:

process.send()

does not compile saying:
error TS2532: Object is possibly 'undefined'.

Happens to me too :

Vue.directive('click-outside', {
  bind: (el, binding, vnode) => {
    const event = ..a function
    if (vnode) {
      vnode.context[binding.expression](event) // Object is possibly 'undefined'.ts(2532)
    }
  }
}

Both codium & compile shows the error. Issue being tracked at #10642

Was this page helpful?
0 / 5 - 0 ratings