Typescript: Object is possibly 'undefined'

Created on 30 Jan 2019  Β·  29Comments  Β·  Source: microsoft/TypeScript


TypeScript Version: 3.4.0-dev.201xxxxx


Search Terms: Object undefined

Code turn strictNullChecks on

// A *self-contained* demonstration of the problem follows...
// Test this by running `tsc` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.
type EventType = 'click' | 'dblclick'

const handlerMap: { [P in EventType]?: any[] } = {}

function addHandler<P extends EventType>(evType: P) {
  const handlerList = handlerMap[evType] || []
  handlerList.push({}) // Error here: Object is possibly 'undefined'
  handlerMap[evType] = handlerList
}

Expected behavior: No Error

Actual behavior: Shows Error

Playground Link: http://www.typescriptlang.org/play/#src=type%20EventType%20%3D%20'click'%20%7C%20'dblclick'%0Aconst%20handlerMap%3A%20%7B%20%5BP%20in%20EventType%5D%3F%3A%20any%5B%5D%20%7D%20%3D%20%7B%7D%0Afunction%20addHandler%3CP%20extends%20EventType%3E(evType%3A%20P)%20%7B%0A%20%20const%20handlerList%20%3D%20handlerMap%5BevType%5D%20%7C%7C%20%5B%5D%0A%20%20handlerList.push(%7B%7D)%20%2F%2F%20Error%20here%3A%20Object%20is%20possibly%20'undefined'%0A%7D%0A

Related Issues:

Duplicate

Most helpful comment

@MufidJamaluddin duplicate of #7719

Workaround is use kelas!.iskelas

All 29 comments

Will be giving this a try.

It's the same issue?

interface State {
    [i: string]: {data?: {id:string}} | undefined
 }

declare var x: State;

const id = 'xx';
const y = x[id] && x[id].data; // Error: Object is possibly 'undefined' (with strictNullChecks
const yId = y && y.id; // correct type – string | undefined

Playground link : https://www.typescriptlang.org/play/#src=interface%20State%20%7B%0D%0A%20%20%20%20%5Bi%3A%20string%5D%3A%20%7Bdata%3F%3A%20%7Bid%3Astring%7D%7D%20%7C%20undefined%0D%0A%20%7D%0D%0A%0D%0Adeclare%20var%20x%3A%20State%3B%0D%0A%0D%0Aconst%20id%20%3D%20'xx'%3B%0D%0A%0D%0Aconst%20y%20%3D%20x%5Bid%5D%20%26%26%20x%5Bid%5D.data%3B%0D%0A%0D%0Aconst%20yId%20%3D%20y%20%26%26%20y.id%3B%0D%0A

29317 should be the fix here (which I have mentioned in @collin5 's PR). Specifically, the type of a || b should be calculated as (typeof a & not FalseyTypes) | typeof b, where FalseyTypes is 0 | false | "" | undefined | null.

@RyanCavanaugh given that, should we move this out of 3.4, since we won't be shipping them in 3.4?

@ktoto your issue is different - since State has an index signature, we don't track refinements on individual property lookups within it - see #17960 and #29042 (and go updoot those issues so they don't sit in the backlog).

I have same issue. :(

Typescript Version : 3.4.5

undefined

@MufidJamaluddin duplicate of #7719

Workaround is use kelas!.iskelas

Same issue as @MufidJamaluddin
I have a checker in place to avoid duplicating code but Typescript ignores it and output this error.

Screenshot 2019-08-06 at 15 45 00

I got the exact same issue since upgrading to newer version 3.5.2. I honestly don't know what to do as this worked for ages. Forcing with ! is no option for me.

@marcj Same error, but as with @ktoto's, the issue has more to do with https://github.com/microsoft/TypeScript/issues/29042 and https://github.com/microsoft/TypeScript/issues/17960. Ultimately, the question is how much TypeScript can be asked to simulate when checking keys. 3.5.3 seems to handle checking of a constant string index whose value was set with a constant string index after initialization, and of a constant variable index whose value was defined on declaration, but not a variable index for a value assigned after initialization.

const myObj: { prop?: number } = {};
myObj['prop'] = 1;
if (myObj['prop']) {
    myObj['prop'] = 1 * myObj['prop']; // No error
}
const field = 'prop'
if (myObj[field]) {
    myObj[field] = 1 * myObj[field]; // Possibly undefined
}
const otherObj = {prop: 1};
if (otherObj[field]) {
    otherObj[field] = 1 * otherObj[field]; // No error
}

Your case stands out because it requires dynamic assignment, dynamic retrieval, and continued access to the original object. Casting workaround that could get tedious:

interface KeyType {setValue: (input: string) => void};
const myObj: { aa?: KeyType} = {};
const key = 'aa';
myObj[key] = {setValue: (input): void => {console.log(input);}}

if (myObj[key]) {
    (myObj[key] as KeyType).setValue('bb');
}

same issue for me with this code: https://www.typescriptlang.org/play/index.html?target=6#code/KYDwDg9gTgLgBASwHY2FAZgQwMbDgYQgFsjMkATAKAG9K565sIl0EBzALgOdbYFcomGAmYBnANx0GyAFbBsMAPxdRMKMjYBtALqSAvpUqhIsRCjRZccABIwYYQi3YChIpHFCoKo7k-6DhZhopeiJgGAALCHIVNQ1JBjgoCD5UWPUkNn1DY2h4ZFQMHDxHXhdApFFgxM0Aa2AAT3SNbS4+CmBWJGByOAAfXzKAtwSGCLswZXpbe1LnYeZ9SSNwPLNCyxKeedcg2kTZeSVmzJ1swwA3TCg4TA5CEjJyAF5qRm3Oaj09SSubsGSYDQMAa1ggABtyGhXgCIEDYA0AHKYMIcADkqFUaJ+hgQ6AAFJg4AAyYm3AB0TD8mlh8JBYMhaHJtOBSJRwG0JLJmEpHxpgNZDKhUGZAoRyLC2nJhwUAEpgnogA

export interface Command
{
    config: Configurations;
    inject?: string[];
}

export interface HttpConfiguration extends Configuration
{
    method: string;
    route: string;
}

export interface Configurations
{
    [key: string]: undefined | Configuration;
    http?:  HttpConfiguration;
};

export interface Configuration
{
    inject?: string[];
}


var a:Command={ config:{}};
var propertyHolder={propertyName:'test'};

if(a && a.config[propertyHolder.propertyName] && a.config[propertyHolder.propertyName].inject)
{
}

Another example without dynamic property access:

import React from "react";

interface IPropsPrivate<T> {
  someField: T;
  maybeRows?: string[];
}

type IProps<T> = T extends string ? never : IPropsPrivate<T>;

class Class1<T> extends React.PureComponent<IProps<T>> {
  public render() {
    const maybeRows = this.props.maybeRows;
    const notUndefined = maybeRows === undefined ? [] : maybeRows;

    notUndefined.filter(() => true); // Error: Object is possibly 'undefined'.

    const twiceGuaranteedUndefined = notUndefined || [];

    twiceGuaranteedUndefined.filter(() => true); // Error: Object is possibly 'undefined'.

    return null;
  }
}

// This works fine though
class Class2<T> extends React.PureComponent<IProps<T>> {
  public render() {
    const { maybeRows = [] } = this.props;

    maybeRows.filter(() => true);

    return null;
  }
}

>>Playground

Another example, tried on 3.7.0-dev.20190928:

type DialogProps = {
  buttons?: {
    primary: boolean;
    secondary?: boolean;
  };
};

function Dialog({ buttons }: DialogProps) {
    const atLeastOneButton = buttons !== undefined;

    if (atLeastOneButton) {
      const label = buttons.primary; 
      // throws "Object is possibly 'undefined' over `buttons`
    }
}

Apparently, the compiler doesn't understand that atLeastOneButton is performing a not-undefined check for the same buttons variable.

Playground link
https://www.typescriptlang.org/play/?ts=Nightly#code/C4TwDgpgBAIglgQwDYHsDmAFATisBnKAXigG8AoKKAIwFdhgUA7PAfgC5SLKows4BbBFhAcqKFEggJGAbi6U8EAMZMAJkJDtq4ydLmUAvnKNkyAMxqMlwOE1iJUaABQlqdBsygGO8ZOmy4eACUnNxQKszAUAjAADJSeMAA8owQAELudsS09EwEAISExJaqEGZwqapQAGTVbrnMAHS8AhpQhcWMpeWVcvJQcGZQTjHxCIkp6ZmMIeRhlBGJUEgIVBBIRPUeeM18gsL63AZkBkA

another example

class Test {
    num?: number;

    constructor(num?: number) {
        this.num = num
    }

    checkIsPositive() {
        return this.num && this.num > 0
    }

    doStuff() {
        if (!this.checkIsPositive()) return;
        console.log(this.num ** 4);
    }
}

playground link: http://www.typescriptlang.org/play/?ssl=16&ssc=2&pln=1&pc=1#code/MYGwhgzhAEAqCmEAu0DeAoaXoDsCuAtgPwBcuhARvAE4Dc6m2wA9jstXsEs9QBT7EyAqtQCUaRtmxIAFgEsIAOgHQAvOQKToAXwZTgM+MADWASQgAFZhDlI5AN3i9xGKVOrwkeajmiyFyoTQAGTBfvJKKgB80AAMWrpaACbMAMpeAGYZzhJu2HIZ0LwAhP5KBkZmlta2Dk6i4h5ePvR5WCxszCDwiiDMAOa8ZYEE0ABUY9AALKKt2LqJ6EA

@rasmus-storjohann-PG gunna need some more information on the shapes of the types in question to get an actual repro of that - I'd also open a new issue, since it looks like a pretty distinct bug (just resulting in the same diagnostic message).

Another example below in case it helps.

http://www.typescriptlang.org/play/?noImplicitReturns=false#code/JYOwLgpgTgZghgYwgAgArAQawK4AcAickAzsgN4BQyyA2phAJ4BcyxYUoA5gLotm31myENgC2AI2i9khSMgC+yAD7JsIACYQYoCOoryKVZDDUIwwAPYhjodeix5ZKABS4MOAkQjEW9j0+IAGmQ4dXUobx9Wdi5g2wgADxYRCWgAShYnZVUNLR11ciNqYBhkZwBCNwdPEhpQ8MjuZRVK90cvYjqwiOJibhp4hO40wuox5AiwbCgQIoVDccnp6yr-Dq6G3v7B7iMDIA

why is this not allowed?

checkIsPositive(num: number | undefined): boolean {
        return num > 0
    }    

playground

why is this not allowed?

checkIsPositive(num: number | undefined): boolean {
        return num > 0
    }    

playground

Because it does not make sense (in a strongly typed language) to supply a non-numerical value to an operation meant to compare two numbers. JavaScript's answer (always false if either argument cannot be converted into a number) is arbitrary. This is correct behavior unrelated to this issue.

@MBerka I disagree. I specifically typed the argument. I know it can be undefined. I am not accessing any object properties/methods. The comparison is valid JS why am I prevented from running?

@gkamperis That's valid JS but bad part of JS which TS whats to get rid of.
Since undefined > 0 === false doesn't mean undefined is smaller than 0, right?

@troy351 num ? (num > 0) : false does not mean num is smaller than 0 either. I do not see the relevance.

This check is about NPEs only. There is no chance an NPE can happen here. So the message is not valid.

@gkamperis Yeah, for the complier, num !== undefined ? (num > 0) : false and num > 0 comes out the same result. But for progammers, it's obvious the first one is better.

TS was made for JS users to make less mistakes and that's how TS did it.

Consider this one

checkIsPositive(num: number | undefined): boolean {
        return !(num <= 0)
}   

Tracking at #7719

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@RyanCavanaugh did you link the wrong issue? That one has been closed since 2018.

Also having this issue

Code

type Key = "key1" | "key2";
type Keys = {
  [P in Key]?: { keyProp: string };
};

const keys: Keys = {
  key1: { keyProp: "keyPropVal" },
};

let someKey!: Key;

if (keys[someKey]) {
  // This shows Object is possibly 'undefined'
  keys[someKey].keyProp;
}

Output

"use strict";
const keys = {
    key1: { keyProp: "keyPropVal" },
};
let someKey;
if (keys[someKey]) {
    // This shows Object is possibly 'undefined'
    keys[someKey].keyProp;
}

Compiler Options

{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "useDefineForClassFields": false,
    "alwaysStrict": true,
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "downlevelIteration": false,
    "noEmitHelpers": false,
    "noLib": false,
    "noStrictGenericChecks": false,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "esModuleInterop": true,
    "preserveConstEnums": false,
    "removeComments": false,
    "skipLibCheck": false,
    "checkJs": false,
    "allowJs": false,
    "declaration": true,
    "experimentalDecorators": false,
    "emitDecoratorMetadata": false,
    "target": "ES2017",
    "module": "ESNext"
  }
}

Playground Link: Provided

Hello All,

The object is possibly 'undefined',

This warning is shown by the editor when we provide the body definition of some variable in the form of the interface and add some of the fields as optional

Eg:-

interface Blog {
  autherName: string;
  contents?: any[],
  id: string
}

While using this interface Blog in our code if we are trying to do some loop on Blog.contents
Eg:-

const newBlog: Blog = JSON.parse(blog);
for (const content of newBlog.contents) {`
   console.log("content ", content );
}

This will error in for loop declaration for (const content of newBlog.contents) because we have said in an interface that contents property in Blob object can be or cannot be there hence we first need to check in code if the property is present then we should use it. As follows

Eg:-

if (newBlog.contents && newBlog.contents.length > 0) {
    for (const content of newBlog.contents) {
      console.log("content ", content );
   }
}

This is one way to resolve this warning.

Happy Coding!

Hello All,

The object is possibly 'undefined',

This warning is shown by the editor when we provide the body definition of some variable in the form of the interface and add some of the fields as optional

Eg:-

interface Blog {
  autherName: string;
  contents?: any[],
  id: string
}

While using this interface Blog in our code if we are trying to do some loop on Blog.contents
Eg:-

const newBlog: Blog = JSON.parse(blog);
for (const content of newBlog.contents) {`
   console.log("content ", content );
}

This will error in for loop declaration for (const content of newBlog.contents) because we have said in an interface that contents property in Blob object can be or cannot be there hence we first need to check in code if the property is present then we should use it. As follows

Eg:-

if (newBlog.contents && newBlog.contents.length > 0) {
    for (const content of newBlog.contents) {
      console.log("content ", content );
   }
}

This is one way to resolve this warning.

Happy Coding!

Thanks alokadhao20,It solved issue for me.

@RyanCavanaugh did you link the wrong issue ? That one has been closed since 2018.

Locking because everyone is posting about all of their "is possibly undefined" code snippets here without context for the original post.

The inability to handle x || [] when x is a type parameter is a current design limitation wherein we need to have some new mechanism for describing higher-order facts about generic type parameters; today if something is T and we know it's truthy or falsy, there's no mechanism for us to better describe its assignability to any given target type. Everything we've tried so far here has been a performance or usability disaster so it's on the back burner for the time being until we can hopefully have some better insight on how to represent this in a more ergonomic/efficient way.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

siddjain picture siddjain  Β·  3Comments

bgrieder picture bgrieder  Β·  3Comments

MartynasZilinskas picture MartynasZilinskas  Β·  3Comments

manekinekko picture manekinekko  Β·  3Comments

jbondc picture jbondc  Β·  3Comments