Search code examples
reactjstypescriptcreate-react-app

string[] is not assignable to type string


I am trying to learn typescript. emphasis on trying.

But the following code gives me an error of string[] is not assignable to type string It gives me the error on the values in between <TodoContext.Provider value={[todos, setotodos]>

Thanks for your help!

import React, { createContext, useState } from "react";

interface Props {
  children: JSX.Element;
}

export const TodoContext = createContext<string[]>([]);

export function TodoComponent({ children }: Props) {
  const [todos, setTodos] = useState<string[] | never>([]);
  return (
    <TodoContext.Provider value={[todos, setTodos]}>
      {children}
    </TodoContext.Provider>
  );
}

export default TodoComponent;

Solution

  • createContext<string[]>([]);
    

    This means that the value will be an array of strings. So for example, you could safely do the following, since todos is an array of strings:

    <TodoContext.Provider value={todos}>
    

    But what you're trying to pass in is value={[todos, setTodos]}. That's an array that contains a string array, and a function. Assuming you want the type information to preserve the order (that index 0 is the string array, and index 1 is the function), you'll do that with a tuple type like this:

    import { Dispatch, SetStateAction } from 'react';
    
    createContext<[string[], Dispatch<SetStateAction<string[]>>]([[], () => {}])
    

    Dispatch<SetStateAction<string[]>> Is the types that react provides for the state setter function. If you wanted to create that type yourself it would be:

    (string[] | ((prevState: string[]) => string[])) => void
    

    In other words, a function that you can either pass a string array into, or you can pass a function into it which will get the previous state and return the new state


    P.S, the never in this type has no effect:

    useState<string[] | never>([]);
    

    It can just be:

    useState<string[]>([]);