Typescript: Why does `tslint` report `TS2531: Object is possibly 'null'.` even I checked it before use?

Created on 19 Jul 2018  ·  3Comments  ·  Source: microsoft/TypeScript

I am using typescript in React project. I have below code in typescript:

        if(this.state.deletedItem !== null) {
                this.props.deleteItem({refItemIdx: this.state.deletedItem.itemIdx});
              }

Below is the type definition:

 interface State {
  deletedItem: ItemDiscountTranItem | null;
}

export class MainView extends React.Component<Props, State> {

  state = {
    deletedItem: null,
  };
  ...

tslint gives me an error TS2531: Object is possibly 'null'. on the object this.state.deletedItem.itemIdx. It says this.state.deletedItem could be null. But I already checked it in the if condition and why it still reports such error?

Question

Most helpful comment

The type of MainView['state']['deletedItem'] is inferred by the compiler as null and only null, because you initialized it to null. You probably expect that since MainView extends React.Component<Props, State> that state would be inferred as State... but subclasses are allowed to have narrower properties than their base classes, and null is narrower than ItemDiscountTranItem | null. So it stayed null even after you checked it. (I'm a little surprised that this.state.deletedItem didn't get narrowed to never, but 🤷‍♂️)

If you want to fix it, annotate state in the initializer to be something like:

state: State = { deletedItem: null };

and the problem will likely go away.


Also please note that Stack Overflow is a better place to ask such questions. When you file an issue here you are presented with this:

Question
The issue tracker is not for questions. Please use Stack Overflow or other resources for help writing TypeScript code.

All 3 comments

The type of MainView['state']['deletedItem'] is inferred by the compiler as null and only null, because you initialized it to null. You probably expect that since MainView extends React.Component<Props, State> that state would be inferred as State... but subclasses are allowed to have narrower properties than their base classes, and null is narrower than ItemDiscountTranItem | null. So it stayed null even after you checked it. (I'm a little surprised that this.state.deletedItem didn't get narrowed to never, but 🤷‍♂️)

If you want to fix it, annotate state in the initializer to be something like:

state: State = { deletedItem: null };

and the problem will likely go away.


Also please note that Stack Overflow is a better place to ask such questions. When you file an issue here you are presented with this:

Question
The issue tracker is not for questions. Please use Stack Overflow or other resources for help writing TypeScript code.

Thanks for your help and my problem get solved. I wonder where the official document I can find to describe this syntax like narrow peroperties, never etc.

@zhaoyi0113 did you ever find where this documentation is served?

Was this page helpful?
0 / 5 - 0 ratings