React & TypeScript: Avoid context default value
Note from the react documentation:
The defaultValue argument is only used when a component does not have a matching Provider above it in the tree.
The way I prefer to do it is by actually specifying that the default value can be undefined
const TodoContext = React.createContext<ITodoContext | undefined>(undefined)
And then, in order to use the context, I create a hook that does the check for me:
function useTodoContext() {
const context = useContext(TodoContext)
if (context === undefined) {
throw new Error("useTodoContext must be within TodoProvider")
}
return context
}
Why I like this approach?
It is immediately giving me feedback on why my context value is undefined
.
For further reference, have a look at this blog post by Kent C. Dodds
There's no way of avoiding declaring the interface and the runtime values, because TS's types disappear at runtime, so you're only left with the runtime values. You can't generate one from the other.
However if you know that you are only ever going to access the context within the TodoContextProvider
component you can avoid initialising TodoContext
by cheating a little bit and just telling TS that what you're passing it is fine.
const TodoContext = React.createContext<TodoContext>({} as TodoContext)
If you do always make sure to only access the context inside of TodoContextProvider
where todos
and setTodos
are created with useState
then you can safely skip initialising TodoContext
inside of createContext
because that initial value will never actually be accessed.