picklepick
picklepick

Reputation: 1607

Initializing useContext Types for Custom Hook

I have difficulties figuring out which types are required in order to make my custom hook work with useContext. I feel like I have tried every possible combination, but it's like a game of 'whack a mole', as soon as I get one part working another breaks.

What I find especially strange is that I get the message: Property 'createFlow' does not exist on type 'APIProps | null', although it's clearly part of APIProps right? My guess is that this is because of the initialization of the context, could someone help me with this?

Thanks!

The code is relatively short, so I'll post everything for easy copy-paste testing:

import axios, { AxiosResponse } from "axios";
import React, { useState, useContext, createContext, FC } from "react";

interface APIProps {
  project?: {};
  setProject?: React.Dispatch<React.SetStateAction<{}>>;
  createProject?: (project: {}) => Promise<AxiosResponse<any>>;
  createFlow?: (
    projectId: string,
    patchData: {
      op: string;
      flow: {
        name: string;
        description: string;
      };
    }
  ) => Promise<AxiosResponse<any>>;
}

const DBContext = createContext<APIProps | null>(null); // what to put here

export const useAPI = () => useContext(DBContext);

const DBProvider: FC = ({ children }) => {
  const [project, setProject] = useState({});

  /**
   * creates new project entry in the db, returns projectId on success
   * @param {*} project object with name, description, provider
   */
  const createProject = (project: { name: string; description: string }) =>
    axios.post(`http://localhost:3000/projects`, project);

  const createFlow = (
    projectId: string,
    patchData: { op: string; flow: { name: string; description: string } }
  ) => axios.patch(`http://localhost:3000/projects/${projectId}`, patchData);

  const value = { project, setProject, createProject, createFlow };

  return <DBContext.Provider value={value}>{children}</DBContext.Provider>;
};

export default DBProvider;
const MyComponent:FC<Props> = ({props}) => {
   // I can't figure out how to get this part to work!
   // Property 'createFlow' does not exist on type 'APIProps | null'
   const { createFlow }: APIProps | null = useAPI();

   return
     <button onClick={
         () => createFlow("id", {op: "", flow: {name: "", description: ""}})
     }>Click</button>
}

Upvotes: 0

Views: 251

Answers (1)

Chris Heald
Chris Heald

Reputation: 62708

createFlow does not exist on null, and you declare your type to be nullable. You have to assert that your context value is not null before using it:

const MyComponent: FC<Props> = ({ props }) => {
  // I can't figure out how to get this part to work!
  // Property 'createFlow' does not exist on type 'APIProps | null'
  const api = useAPI();

  return api && <button
    onClick={() =>
      api.createFlow("id", { op: "", flow: { name: "", description: "" } })
    }
  >
    Click
  </button>;
};

Upvotes: 1

Related Questions