skip to Main Content

I am using createContext in Next.js to create a dark mode button; here’s the ThemeContext.tsx, it’s originally a normal jsx file; I am trying to convert it to TypeScript.

"use client";

import { useState, createContext } from "react";

type ThemeContextType = "light" | "dark";

interface ChildrenProps {
  children: React.ReactNode;
}

export const ThemeContext = createContext<ThemeContextType>("light");

export const ThemeProvider = ({ children }: ChildrenProps) => {
  const [mode, setMode] = useState<string>("dark");

  const toggle = (): void => {
    setMode((prev) => (prev === "dark" ? "light" : "dark"));
  };
  return (
    <ThemeContext.Provider value={{ toggle, mode }}>
      <div className={`theme ${mode}`}>{children}</div>
    </ThemeContext.Provider>
  );
};

I got the error from the value in ThemeContext.Provider value={{toggle, mode}}>

Type '{ toggle: () => void; mode: string; }' is not assignable to type 'ThemeContextType'.ts(2322)

index.d.ts(329, 9): The expected type comes from property 'value' which is declared here on type 'IntrinsicAttributes & ProviderProps<ThemeContextType>'

2

Answers


  1. You need to update ThemeContextType, because, as of now, it makes it so the value of the provider can only accept a string equal to "light" or "dark". This should work:

    "use client";
    
    import { useState, createContext } from "react";
    
    type ModeType = "light" | "dark";
    type ThemeContextType = {
      mode: ModeType;
      toggle: () => void;
    };
    
    interface ChildrenProps {
      children: React.ReactNode;
    }
    
    export const ThemeContext = createContext<ThemeContextType>({ mode: "light", toggle: () => {} });
    
    export const ThemeProvider = ({ children }: ChildrenProps) => {
      const [mode, setMode] = useState<ModeType>("dark");
    
      const toggle = (): void => {
        setMode((prev) => (prev === "dark" ? "light" : "dark"));
      };
    
      return (
        <ThemeContext.Provider value={{ toggle, mode }}>
          <div className={`theme ${mode}`}>{children}</div>
        </ThemeContext.Provider>
      );
    };
    
    Login or Signup to reply.
  2. The error you’re seeing is because the value you’re providing to the ThemeContext.Provider does not match the expected type of ThemeContextType. The value prop of ThemeContext.Provider expects a value of type ThemeContextType, which is defined as "light" | "dark". However, you are passing an object with properties toggle and mode, which does not match the expected type.

    To fix this, you can create a separate interface for the context value and use it as the type for the ThemeContext.Provider value. Here’s an updated version of your code:

    import { useState, createContext } from "react";
    
    type ThemeContextType = "light" | "dark";
    
    interface ThemeContextValue {
      toggle: () => void;
      mode: ThemeContextType;
    }
    
    interface ChildrenProps {
      children: React.ReactNode;
    }
    
    export const ThemeContext = createContext<ThemeContextValue>({
      toggle: () => {},
      mode: "light",
    });
    
    export const ThemeProvider = ({ children }: ChildrenProps) => {
      const [mode, setMode] = useState<ThemeContextType>("dark");
    
      const toggle = (): void => {
        setMode((prev) => (prev === "dark" ? "light" : "dark"));
      };
    
      const contextValue: ThemeContextValue = {
        toggle,
        mode,
      };
    
      return (
        <ThemeContext.Provider value={contextValue}>
          <div className={`theme ${mode}`}>{children}</div>
        </ThemeContext.Provider>
      );
    };

    In this updated code, we define the ThemeContextValue interface to represent the structure of the context value. We provide default values for the toggle and mode properties in case they are not provided. We then explicitly set the type of the contextValue variable to ThemeContextValue and pass it as the value for ThemeContext.Provider.

    With these changes, the error should be resolved, and you should be able to use the ThemeProvider and ThemeContext in your Next.js app without any issues.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search