I want to infer the values of a nested selector. Meaning that the second selector uses the result of the first selector as an argument to select a sub piece of this value.
function store<
T,
Selector extends (a: T) => unknown,
ReturnValue extends ReturnType<Selector>,
NestedSelector extends (a: ReturnValue) => unknown,
ReturnValueNestedSelector extends ReturnType<NestedSelector>
>(state: T, selector: Selector) {
const get = () => selector(state) as ReturnValue;
const getNested = (nestedSelector: NestedSelector) =>
nestedSelector(selector(state) as ReturnValue) as ReturnValueNestedSelector;
return {
get,
getNested,
};
}
const initialData = {
foo: {
bar: {
id: 1,
},
},
};
const myStore = store(initialData, (a) => a.foo.bar);
const a = myStore.get(); // { id: number }
const result = myStore.getNested((state) => {
return state.id; // number
}); // unknown
The first selector is working okayish (I still need to cast the return value) but the getNested function returns unknown. Is there a way to solve this in TS?
CodePudding user response:
You can simplify it a bit:
function store<
T,
ReturnValue,
>(state: T, selector: (a: T) => ReturnValue) {
const get = () => {
return selector(state)
};
const getNested = <R,>(nestedSelector: (a: ReturnValue) => R) =>
nestedSelector(get())
return {
get,
getNested,
};
}
const initialData = {
foo: {
bar: {
id: 1,
},
},
};
const myStore = store(initialData, (a) => a.foo.bar);
const a = myStore.get(); // { id: number }
const result = myStore.getNested((state) => state.id); // number
You need to add extra generic for callback return type. TS is able to infer it. If you are interested on function arguments inference you can check my article