'useState – Are nested values rolled out progressively?

I'm getting a TypeError, and I can't figure out why:

TypeError: undefined is not an object (evaluating 'data.nested.value')
The above error occurred in the <MyComponent> component:

I am aware that one can't read properties of null-ish values (null and undefined). The problem is that neither data, nor data.nested isn't supposed to be null-ish in the first place, – I'm using TypeScript with "strict": true, so I'm pretty sure in that (also, I've logged the value).


My setup is that I have a component, which uses a custom hook, which in turn fetches some data from server (the indicated key lines are explained below):

interface Data {
  nested: { value: string }; // (1)
}
export function MyComponent() {
  const data = useData();

  if (data == null) return null; // (2)

  return (
    <MyOtherComponent
      prop={data.nested.value} // (3)
    />
  );
}
import { useState, useEffect } from 'react';
import { getData } from './api/get-data';

export function useData() {
  const [data, setData] = useState<Data>(); // (4)

  useEffect(() => {
    (async () => {
      const result = await getData(); // (5)

      if (result.error) {
        console.error(result.error);
      } else {
        setData(result.value);
      }
    })();
  }, []);

  return data ?? null // (6)
}
  1. Data instances are defined to have .nested property, which is always an object, and is never null or undefined.
  2. The data itself, however, can be null (see (4) and (6)). If it is, then <MyComponent /> shouldn't render anything (i.e., return null).
    • if I change if (data == null) to if (!data?.nested) the error goes away. But in the real app I have not just one but many .nested properties, so this explicit check would be unreadable. Also, this would be a weird check, since it shouldn't be null-ish in the first place.
  3. The value data.nested.value is used in <MyOtherComponent />, – this is where the error is thrown.
  4. The get/set suite for data is created with React's useState. There's no initialiser provided, so data is initially undefined.
  5. The getData API function never throws and resolves to a utility object with .value and .error properties (similar to how Promise.allSettled works).
    • most importantly, the .value is always a complete instance of Data with all of its properties, returned from the server.
  6. If data is not set (is undefined), the hook returns null instead.

Given all that, there seems to be a point where data is an object, but data.nested is null-ish. I'm pretty sure, in plain JavaScript this is impossible. But maybe React adds something on its own? Such as, for example, progressive rollout of nested values?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source