In the process of developing a state manager library for React, I came up with an idea to implement a helper function that would allow users to easily set deeply nested states from outside of React using a selector. The helper function I have currently looks something like this:
type NestedStateSetter<State> = <Selected = State>(
update: Selected | (() => Selected) | (() => Promise<Selected>),
selector?: (state: State) => Selected
) => Promise<Selected>;
const initialState = {
a: {
b: {
c: 0,
},
},
};
const setState: NestedStateSetter<typeof initialState> = (update, selector) => {
throw "Yeet"
};
setState(1, (state) => state.a.b.c) // Ok
setState(() => 2, (state) => state.a.b.c) // Ok
setState(async () => 5, (state) => state.a.b.c) // Not ok
However, when trying to use 'setState' with async function in the third call, it leads to an error related to type mismatch on the (state) => state.a.b.c
parameter:
Argument of type '(state: { a: { b: { c: number; }; }; }) => number' is not assignable to parameter of type '(state: { a: { b: { c: number; }; }; }) => Promise'. Type 'number' is not assignable to type 'Promise'.(2345)
TypeScript Playground link
Stackblitz link
I considered implementing a curried function to address this issue, but that might introduce breaking changes which I want to avoid if possible.