comiventor
comiventor

Reputation: 4122

Handling optional field in Typescript

Following is my React Component code snippet where one of the fields is optional. Being optional, I have to initialize it undefined but this makes it tough to later use it even after type check. I am not sure how to tackle this. I am using typescript version 3.2.2.

interface State {
  open: boolean;
  selected?: SelectedFieldType;
}

class CFilter extends React.Component<Props, State> {
  state = {
    open: false,
    selected: undefined
  };

  onOperatorValueChange = (value: any) => {
    if (typeof this.state.selected !== undefined) {
      console.log(this.state.selected.value); // ERROR: Object is possibly undefined (property): selected undefined
      this.setState({
        selected: {
          ...this.state.selected, // ERROR: Spread types may only be created from object types
          value: value
        }
      });
    }
  };

  render() {
    return (<span>some jsx</span>);
  }
}

If I don't intialize selected, it will throw me an error

Property selected doesn't exist

Upvotes: 3

Views: 3070

Answers (2)

Anya
Anya

Reputation: 1398

Type 'null' is not assignable to type 'SelectedFieldType | undefined' sounds odd... maybe you could try to add just for testing a pipe allowing null value to SelectedFieldType. But it is bizarre to have to do it.

interface State {
  open: boolean;
  selected?: SelectedFieldType | null;
}

The observation from @jcalz also seems very good. You should try it.

If it don't work, you could try to re-write your code to something like:

class CFilter extends React.Component {
  state: State = {
    open: false,
    selected: null,
  };

  onOperatorValueChange = (value: any) => {
    if (this.state.selected) {
      this.setState({
        selected: { 
          ...this.state.selected,
          value
        }
      });
    }
  };

I have tested on this stackblitz and it seems to work fine with no errors.

Upvotes: 0

jcalz
jcalz

Reputation: 327624

I don't have react set up so I can't test this, but my guess is that you should annotate the type of state to State when you initialize it, like

  // note the annotation
  state: State = {
    open: false,
    selected: undefined
  };

instead of letting the compiler infer the type. It's quite possible that the compiler thinks that CFilter['state'] is narrower than State (CFilter extends React.Component<Props, State> means state can be any type that extends State.) and that CFilter['state']['selected'] is always undefined. If so, then this.state.selected will always be considered undefined and it's impossible to change that with a null-check (it is unfortunate that the error message complains about it being "possibly" undefined when it thinks it is necessarily undefined, but that's how it is.)

Try the explicit annotation and see if it fixes the problem. Hope that helps. Good luck!

Upvotes: 4

Related Questions