Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Infer return value of nested selectors

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?

Playground

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

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

Playground

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

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading