2

I have created the following context using React createContext:

import { useBoolean } from "@chakra-ui/react"
import { createContext, FC } from "react"

type useBooleanReturn = ReturnType<typeof useBoolean>

export const MobileContext = createContext<
  [show: useBooleanReturn[0], setShow: useBooleanReturn[1]] | undefined
>(undefined)

// --- PROVIDER
const MobileProvider: FC = ({ children }) => {
  const [show, setShow] = useBoolean(false)

  return (
    <MobileContext.Provider value={[show, setShow]}>
      {children}
    </MobileContext.Provider>
  )
}

export default MobileProvider

As far as I can tell, this works as it should (at least I am not getting any typescript errors).

I now want to "consume" that context as follows:

import * as React from "react"

import MobileProvider, { MobileContext } from "./context.mobile"

const Mobile = () => {
  const [show, setShow] = React.useContext(MobileContext)
  ...
}

export default Mobile

It is here that I get some typescript errors -- in particular, [show, setShow] is underlined with the red squiggly line and the following message:

Type '[
  show: boolean, 
  setShow: { 
    readonly on: () => void; 
    readonly off: () => void; 
    readonly toggle: () => void; 
    }
  ] | undefined' is not an array type.ts(2461)

I don't understand why this is not an array type or how to fix this.

Any ideas?

Thanks.

Moshe
  • 6,011
  • 16
  • 60
  • 112

3 Answers3

2

I'd do it like this

const [show, setShow] = React.useContext(MobileContext) ?? []

Only thing here is that show and setShow may be undefined. You can actually set default values for these if you want:

const [
  show = false,
  setShow = () => {},
] = React.useContext(MobileContext) ?? []

Though, setting the default value could mess up the type of show and setShow, for example you could set show = 1. So, you know...use responsibly.

Paul Huynh
  • 2,462
  • 1
  • 11
  • 11
0
export const MobileContext = createContext<
  [show: useBooleanReturn[0], setShow: useBooleanReturn[1]] | undefined
>(undefined)

You've specified that while the value might be an array, it might also be undefined. If that's correct, then you will need to check for undefined before interacting with it as though it's an array:

const Mobile = () => {
  const value = React.useContext(MobileContext);
  if (value) {
    const [show, setShow] = value;
    // do something with show and setShow
  }
}

On the other hand, if you don't want undefined to be a possibility, then update the initialization of the context:

export const MobileContext = createContext<
  [show: useBooleanReturn[0], setShow: useBooleanReturn[1]]
>([false, () => {}])
Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
  • I don't want undefined to be a possibility, I only added it because React Context requires a default value. With that said, when I try your solution, I get a different error for `() => {}`. Namely: `Type '() => void' is missing the following properties from type '{ readonly on: () => void; readonly off: () => void; readonly toggle: () => void; }': on, off, toggle`. Any idea how to fix that? – Moshe Jun 29 '21 at 13:40
  • You'll need to fill in a default value that matches the type `useBooleanReturn[1]`. I took a guess what that might be and did an empty function, but apparently that doesn't match. – Nicholas Tower Jun 29 '21 at 16:41
0

You are simply saying it can be undefined, and if it's undefined then it cannot be destructured in that way.

It's pretty easy to see that this will throw an error: const [show, setShow] = undefined;

So either check if the value returned from the useContext is undefined, or initialize it with dummy data.

szilagyi.sandor
  • 204
  • 1
  • 6