Lesson 14. Better hooks with TypeScript 2. Typing contexts
To type your contexts, give the type when you call createContext. It has to be
the full type of the context’s value. So if your context contains a theme
value and two ways to set it, it can look like that:
type Theme = 'light' | 'dark'const ThemeContext = createContext<{theme: ThemesetTheme: (theme: SetStateAction<Theme>) => voidtoggle: () => void}>({theme: 'light',setTheme: () => {},toggle: () => {},})
Note that when using TypeScript, you need to give createContext a default
value with the same type as the context. In my opinion, this is a little
annoying because this default value may never be used if you pass the initial
value as a prop to the Provider component. This is why here we use an object
with empty functions as default value.
With a typed context, the hook(s) you’ll create to access it will be automatically typed by TypeScript, meaning that you shouldn’t have to give any explicit type:
const useTheme = () => useContext(ThemeContext)const ThemeSwitcher = () => {const { theme, toggle } = useTheme()return (<p>Theme: {theme} <button onClick={() => toggle()}>Toggle</button></p>)}
Last piece of the puzzle: if you create a custom provider component for your context, the value you pass to the context’s provider must match the context’s type.
const ThemeProvider = ({defaultTheme,children,}: {defaultTheme: Themechildren: ReactNode}) => {const [theme, setTheme] = useState(defaultTheme)const toggle = () => setTheme((th) => (th === 'light' ? 'dark' : 'light'))return (<ThemeContext.Provider value={{ theme, setTheme, toggle }}>{children}</ThemeContext.Provider>)}const App = () => {return (<ThemeProvider defaultTheme="light"><ThemeSwitcher /></ThemeProvider>)}