4
type ContextProps<T = object> = {
  store: T,
  updateStore: React.Dispatch<T>
};

export default React.createContext<Partial<ContextProps>>({}); // is there any way to pass the generic? so store can correct type

export function Provider<T, K>(props: T & { store: K }) {
  const [globalState, updateStore] = React.useState(props.store);
  const value = React.useMemo(
    () => ({
      store: globalState,
      updateStore,
    }),
    [globalState],
  );

  return <StateMachineContext.Provider value={value} {...props} />;
}

Is there any way to pass generic into Context, so value can have the correct type?

2
  • 1
    The only way I can semi achieve what you are asking is to type it on the other end when you call useContext<Type>(Context);. I think this is the best you are going to get as components making use of your context could appear under any instance of a provider for the context and each of these providers could have different generic types meaning typescript can't infer generic types for the consumer as it would have to assume the location of the component in the react tree. This is my understanding of it anyway. Commented Nov 10, 2020 at 4:14
  • Thank you for sharing solution @JacobSmit Commented Nov 10, 2020 at 4:22

1 Answer 1

6

pass the type when creating the context, remember to create it outside the components.

type ContextProps<T = object> = {
  store: T,
  updateStore: React.Dispatch<T>
};

function createGenericContext<T extends object> () {
  return React.createContext<Partial<ContextProps<T>>>({}); 
}

const StateMachineContext = createGenericContext<{type: 'a'}>();
// or just
const StateMachineContext = React.createContext<Partial<ContextProps<{type: 'a'}>>>({});

export function Provider<T, K>(props: T & { store: K }) {
  const [globalState, updateStore] = React.useState(props.store);
  const value = React.useMemo(
    () => ({
      store: globalState,
      updateStore,
    }),
    [globalState],
  );

  return <StateMachineContext.Provider value={value} {...props} />;
}
Sign up to request clarification or add additional context in comments.

2 Comments

im getting: Type 'K' is not assignable to type '{ type: "a"; } | undefined'.
This is a good solution, but just to note this won't work if the component itself receives a generic as you can't create the context outside the component, since it won't know about the generic. This might be obvious, but it took me a while to realise it.

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.