1

I'm new to TS and trying to update code that I inherited from a former employee. I know it's TS related and have tried different types not able to resolve it. Any assistance would be great. Thanks in advance.

Here's the code:

import React from 'react';

export interface HistoryType {
  history?: number;
  setHistory: (value: number) => void;
}

const HistoryContext = React.createContext<HistoryType | undefined>(undefined);

export const HistoryProvider: React.FC = ({ children }) => {
  const [history, setHistory] = React.useState();
  return (
    <HistoryContext.Provider value={{ history, setHistory}}>
      {children}
    </HistoryContext.Provider>
  );
};

export const useHistoryState = () => {
  const context = React.useContext(HistoryContext);
  if (context === undefined) {
    throw new Error('useHistoryState error');
  }
  return context;
};

Screenshot of the error:

error

1 Answer 1

1
const [history, setHistory] = React.useState()

Since no type is specified here, typescript has to try to infer it. It sees that undefined is implicitly being passed to use state, so it assumes the state is (and always will be) undefined. So that means that setHistory expects to be passed undefined.

You will need to specify the type yourself to say that it can either be a number, or undefined:

const [history, setHistory] = React.useState<number | undefined>();

Or if it's always supposed to be a number, you can do that too, but you'll need to provide an initial value which is a number:

const [history, setHistory] = React.useState<number>(42);

P.S: This is unrelated to your question, but i notice this code is employing a common mistake: You're creating a brand new object on every render and passing it as the context value.

value={{ history, setHistory }}>

Since there's a new value on every render, it will force anything that's consuming the context to rerender even if history and setHistory did not change. To fix this you should memoize the value so it only gets recomputed when it actually changes:

  const value = React.useMemo(() => {
    return { history, setHistory };
  }, [history]);

  return (
    <HistoryContext.Provider value={value}>
      {children}
    </HistoryContext.Provider>
  );
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Nicholas for the solution. I also modified the code and included useMemo.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.