11

I'm converting my React project to Typescript.

I have this piece of state:

AdminBlogPostContainer.tsx

const [blogPost,setBlogPost] = useState<null | BLOGPOST>(null);

return(
  <AdminBlogPostPage
    blogPost={blogPost as BLOGPOST}
    setBlogPost={setBlogPost}
  />
);

AdminBlogPostPage.tsx

interface AdminBlogPostPage {
  blogPost: BLOGPOST,
  setBlogPost:            // <---- WHAT SHOULD I USE AS TYPE HERE ?
}

const AdminBlogPostPage: React.FC<AdminBlogPostPage> = (props) => {
  console.log("Rendering AdminBlogPostPage...");

  return(
    // ...
  );
};

export default AdminBlogPostPage;

This is the error message:

enter image description here

cbdeveloper
  • 27,898
  • 37
  • 155
  • 336
  • You shouldn't change parent state from children anyway – Roberto Zvjerković Aug 28 '20 at 12:25
  • Thanks for your reply. But regardless of whether I should be changing state from parent on children, does anybody know what type I should use for the `setState` function in that case? – cbdeveloper Aug 28 '20 at 13:04
  • Can't close as a duplicate since the answer is not accepted, but otherwise should be... https://stackoverflow.com/q/63551792 – Patrick Roberts Aug 28 '20 at 13:13
  • @PatrickRoberts thanks!! That is what I was looking for. So in my case I should use: `React.Dispatch>` ? Feel free to answer here and I'll accept your answer if it works. – cbdeveloper Aug 28 '20 at 13:15
  • Appreciate the accepted answer, went ahead and deleted my answer from the other post and made this the canonical duplicate instead. – Patrick Roberts Aug 28 '20 at 13:28
  • Quick example for visitors coming here from Google: `const [todos, setTodos] = useState>([])` – aderchox Jan 20 '22 at 14:01

2 Answers2

17

Let's start with some relevant type definitions from @types/react.

declare namespace React {
    // ...
    type SetStateAction<S> = S | ((prevState: S) => S);
    // ...
    type Dispatch<A> = (value: A) => void;
    // ...
    function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
    // ...
}

From this we can already deduce the type of setBlogPost in the statement

const [blogPost, setBlogPost] = useState<null | BLOGPOST>(null);

which is Dispatch<SetStateAction<null | BLOGPOST>>, but let's break that down to see what each part means.

setBlogPost: (value: null | BLOGPOST | ((prevState: null | BLOGPOST) => null | BLOGPOST)) => void;

Digesting that one piece at a time working from the outside in, we get the following explanation:

  • setBlogPost: (value: ...) => void

    setBlogPost is a function that accepts a parameter value and returns void.

    • value: null | BLOGPOST | ((prevState: ...) => null | BLOGPOST)

      value is either null, a BLOGPOST, or a function that accepts a parameter prevState and returns null or a BLOGPOST.

      • prevState: null | BLOGPOST

        prevState is either null or a BLOGPOST.

Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
-2
interface AdminBlogPostPage {
  blogPost: BLOGPOST;
  setBlogPost: Function;            // <---- You may use the Function type here
}
CHEEKATLAPRADEEP
  • 12,191
  • 1
  • 19
  • 42
ZakirK
  • 25
  • 5
  • 2
    Typescript errors out and does not suggest this OOTB: Don't use `Function` as a type. The `Function` type accepts any function-like value. It provides no type safety when calling the function, which can be a common source of bugs. It also accepts things like class declarations, which will throw at runtime as they will not be called with `new`. If you are expecting the function to accept certain arguments, you should explicitly define the function – Steven Grimaldo Nov 28 '21 at 05:40