Reputation: 2510
Apologies for the somewhat opaque title, but I am having difficulties being more precise here.
So I have a Context/Reducer Logic, where I initialise the context with some values. I then have a reducer Logic on a custom Provider and use useMemo
to calculate values
. When trying to access one on of those values (that isn't in the state/initialState) on a component typescript gets angry at me and tells me that said value does not exist on State. What is the best way to remedy this warning?
I have the following definition of a Context/Reducer.
interface State {
displaySidebar: boolean
}
const initialState = {
displaySidebar: false
}
type Action =
| {
type: 'OPEN_SIDEBAR'
}
| {
type: 'CLOSE_SIDEBAR'
}
const UIContext = React.createContext<State>(initialState)
UIContext.displayName = 'UIContext'
const uiReducer = (state: State, action: Action): State => {
switch (action.type) {
case 'OPEN_SIDEBAR': {
return {
...state,
displaySidebar: true,
}
}
case 'CLOSE_SIDEBAR': {
return {
...state,
displaySidebar: false,
}
}
}
}
const UIProvider: FC = (props) => {
const [state, dispatch] = React.useReducer(uiReducer, initialState)
const openSidebar = (): void => dispatch({ type: 'OPEN_SIDEBAR' })
const closeSidebar = (): void => dispatch({ type: 'CLOSE_SIDEBAR' })
const value = useMemo(
() => ({
...state,
openSidebar,
closeSidebar,
}),
[state]
)
return <UIContext.Provider value={value} {...props} />
}
export const useUI = () => {
const context = React.useContext(UIContext)
if (context === undefined) {
throw new Error(`useUI must be used within a UIProvider`)
}
return context
}
export const ManagedUIContext: FC = ({ children }) => (
<UIProvider>
<ThemeProvider>{children}</ThemeProvider>
</UIProvider>
)
now when I try to use const {closeSidebar} = useUI()
in a component typescript gets angry with me and tells me that Property 'closeSidebar' does not exist on type 'State'.
I get that, but I was not able to figure out how to properly add closeSidebar
to the React.Context
type.
Upvotes: 1
Views: 169
Reputation: 5036
When you create context you tell TS that its type will be State
, so it doesn't expect anything else to be there. If you want to add additional fields you can create an intersection type, state + methods, either as a named type of just React.createContext<State & {openSidebar : ()=> void, closeSidebar: ()=> void}>
. Note that as your initial state doesn't have methods you either need to make them optional or provide some sort of dummy versions.
Upvotes: 1