Home > database >  initialize useState empty but remove undefined type
initialize useState empty but remove undefined type

Time:08-12

Ok so here is my issue.

interface Example {
    name: string
}
const [name, setName] = useState<Example>()
const fetchedData = fetch().json()
setName(fetchedData)

the type of name is <Example | undefined> at the moment which messes with my components downstream.

when i fetch the data i also set a isFetched variable to true, and the components that rely on my data only render in this case, so the variable "name" is never undefined when passing it to the respective component. However now all my downstream components that rely on the .name property are complaining, because the variable could be undefined

CodePudding user response:

This is because of how TypeScript works. Basically, even though you know that name is never undefined when isFetched is true, TypeScript's static analysis is not clever enough to work this out. As far as its concerned, name could be undefined even though isFetched is true. Typescript does not know the relationship between these variables (unless you tell it, see option 3).

Whilst this seems frustrating, it actually makes sense. Imagine if later down the line you or someone else set isFetched to true but forgot to set the data...your app would error. TypeScripts purpose is to lock down these possibilities to give you stronger guarantees. There's no problem now, but as your code grows, it could be a problem in the future.

You have 3 options

  1. Change your conditional that checks isFetched to also check name. For example isFetched && name !== undefined.
  2. Tell typescript you are sure about this and before you pass name as a prop to the sub components, add a non-null assertion operator after it. I.e. name!. Be careful with using this. Whilst its cheap and very tempting, you are basically opting out of TypeScript safety so using it routinely can degrade the robustness of your code unless youre sure.
  3. The fancy option -- merge your fetching and data vars into one object, and let typescript know what the valid combinations are using a discriminated union:

type Example = {name: string, isFetched : true} | {name: undefined, isFetched: false}

// ...

const [name, setName] = useState<Example>({name: undefined, isFetched: false})

// ...

setName({name: fetchedData, isFetched: true })

// Doing a conditional on `isFetched` will mean everything inside that if-block will have `name` as string and not string or undefined.
  • Related