Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Typescript empty object for react state

I am trying to create a type for a specific object that can be empty, let’s start at the bottom and work our way up to the React class.

Note: I am not using hooks, but even f your answer was in hooks, it can’t be that hard to translate.

We first need to define the state for our class:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

export default interface CharacterInventoryTabsState {
    table: string;

    dark_tables: boolean;

    loading: boolean;

    inventory: Inventory | {};
}

The issue is the inventory property. So lets look at the Inventory type:

export default interface Inventory {

    equipped: InventoryDetails[] | [];

    inventory: InventoryDetails[] | [];

    quest_items: InventoryDetails[] | [];

    usable_items: InventoryDetails[] | [];

    savable_sets: SetDetails[] | [];

    usable_sets: SetDetails[] | [];

    sets: {[key: string]: InventoryDetails[] | []}

    set_equipped: boolean;
}

The inventory object is made up of other objects and their associated types. Fantastic. So lets look at the react class:

The below is just a snippit of the class.

export default class CharacterInventoryTabs extends React.Component<any, CharacterInventoryTabsState> {

constructor(props: any) {
    super(props);

     // ...
 
    this.state = {
        table: 'Inventory',
        dark_tables: false,
        loading: true,
        inventory: {} as Inventory, // I saw this trick to initialize "empty objects"
    }
}

componentDidMount() {
    watchForDarkModeInventoryChange(this);

    (new Ajax()).setRoute('character/'+this.props.character_id+'/inventory').doAjaxCall('get', (result: AxiosResponse) => {
        this.setState({
            loading: false,
            inventory: result.data, // => Here we initialize inventory but ...
        });
    }, (error: AxiosError) => {
        console.log(error);
    })
}

// ... some where in the render method we do:

render() {
    // ... Loader logic so we would never access the state until loading was set to false.
    return(
        <InventoryTable dark_table={this.state.dark_tables} character_id=. {this.props.character_id} inventory={this.state.inventory.inventory} />
    );
}

}

The issue is simple: Property ‘inventory’ does not exist on type ‘{} | Inventory’.   Property ‘inventory’ does not exist on type ‘{}’.

Well duh, its not initialized till after the ajax call and I have a "if loading show the loader jazz" so it would "technically be initialized after the ajax call" but how do I make typescript be quiet about this, aside from the dreaded: any.

I saw the trick of const var = {} as Type in another stack question related to this, but alas it does not seem to work for me.

What is the correct way to handle a situation like this?

>Solution :

  1. Well, first of all get rid of any ases – they’re you pinky-swearing that "I know perfectly well what I’m doing with my types".
  2. Make the type for the inventory state field something like inventory: Inventory | null, and initialize it with null.
  3. In your render function, destructure inventory into a local: const {inventory} = this.state;. (This helps TS with inference.)
  4. if(inventory === null) return <Loading />;
  5. The if/return will help TypeScript narrow the type of inventory for the rest of the render function; after all, if it’s not null, it can only be a real Inventory.

Unless you need loading for anything else, you could also drop it from state, since you can tell whether you’re loading based on just whether inventory !== null.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading