I have a pretty tricky TypeScript issue with generics and partial.
A playground for this issue is here
I will explain the issue using React terminology, although it has nothing to do with React directly.
There's a custom React hook, that basically creates a reducer, using useReducer, and it contains some common properties, along with a generic data property.
Let's pretend this is the hook:
interface IState<T> {
some: string;
data: T;
}
type Action<T> = { type: 'UPDATE_STATE'; payload: Partial<T> };
const foo = <T>(initalState: T) => {
const state: IState<T> = { some: 'foo', data: initalState };
const dispatch = (action: Action<T>) => {
// do something
}
return {state, dispatch};
};
In addition, there's another custom hook, that actually extends the first one by adding additional common properties to the state reducer:
interface MyBar {
extraData: string;
}
const bar = <T>(initialState: T) => {
const {state, dispatch} = foo<T & MyBar>({ ...initialState, extraData: 'some data' });
return { state, dispatch };
}
Now, a typical usage would be:
const baz = () => {
const { state, dispatch } = bar<IMyState>({ name: 'mor' });
console.log(state, dispatch)
}
So in baz, my state object will be:
{
"extraData": "some data",
"some": "foo",
"data": {
"name": "mor"
}
}
So far so good. Now I want to do the following change:
const bar = <T>(initialState: T) => {
const {state, dispatch} = foo<T & MyBar>({ ...initialState, extraData: 'some data' });
**dispatch({ type: 'UPDATE_STATE', payload: { extraData: 'changed' } });**
return { state, dispatch };
}
And I get:
Type '{ extraData: "changed"; }' is not assignable to type 'Partial<T & MyBar>'.(2322)
input.ts(7, 42): The expected type comes from property 'payload' which is declared here on type 'Action<T & MyBar>'
I am not sure why that happens, since bar passes the generic type alongside with the extra data, I'd expect that foo would be able to allow it.
I'd appreciate any advice!