Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typed mapGetters, mapActions and such #73

Open
Papooch opened this issue Aug 20, 2021 · 1 comment
Open

Typed mapGetters, mapActions and such #73

Papooch opened this issue Aug 20, 2021 · 1 comment

Comments

@Papooch
Copy link

Papooch commented Aug 20, 2021

Are there any plans to add typed variants of these helper functions? I might give it a try myself but I don't know if something like that is possible with the current implementation. I guess you could pass the store as a parameter to extract the types?

something like:

computed: {
   ...mapDirectGetters(this.$store, ['username', 'email'])
}

I'd like to hear your thoughts on this.

EDIT: I mean, we can just return the mapDirectGetters from createDirectStore so we don't have to pass this.$store

so it would be:

// store/index.ts
export { store, mapDirectGetters } = createDirectStore( ... )

and then

computed: {
   ...mapDirectGetters(['username', 'email'])
}
@Papooch
Copy link
Author

Papooch commented Aug 26, 2021

Ok, I have a proof of concept:

// pickable.ts
export type Primitive = string | number | boolean | bigint | null | void | symbol | Function;

export type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...0[]];

export type Leaves<T, U extends string = never, L extends number = 1> = [
    L,
] extends [never]
    ? U
    : {
          [K in keyof T & string]: [U] extends [never]
              ? T[K] extends Primitive
                  ? K
                  : Leaves<T[K], K, Prev[L]>
              : T[K] extends Primitive
              ? `${U}.${K}`
              : Leaves<T[K], `${U}.${K}`, Prev[L]>;
      }[keyof T & string];

export type ResolvePath<T, K> = K extends keyof T
    ? T[K]
    : K extends `${infer F}.${infer L}`
    ? ResolvePath<ResolvePath<T, F>, L>
    : never;

export type LastKey<T extends string> = T extends `${string}.${infer L}`
    ? LastKey<L & string>
    : T;

export function cherryPick<T, K extends readonly Leaves<T>[]>(
    obj: T,
    keys: K | [],
): { [K2 in K[number] as LastKey<K2>]: ResolvePath<T, K2> } {
    const ret = {} as any;
    keys.forEach((key) => {
        const path = key.split('.');
        let prop = obj as any;
        path.forEach((segment) => {
            prop = prop[segment as keyof typeof prop];
        });
        ret[path.pop() as keyof typeof ret] = prop;
    });
    return ret;
}

export function makePickable<T>(
    obj: T,
): <K extends readonly Leaves<T>[]>(
    keys: K | [],
) => { [K2 in K[number] as LastKey<K2>]: ResolvePath<T, K2> } {
    return (keys: any) => cherryPick(obj, keys) as any;
}
// store.mappers.ts
import { makePickable } from './pickable'
import store from './store'

export const mapDirectGetters = makePickable(store.getters);
export const mapDirectMutations = makePickable(store.commit);
export const mapDirectActions = makePickable(store.dispatch);

Right now you have to import store and pass it as the first parameter (and getters have to be spread into data, not computed for the types to work), but I guess it's a good start.

Edit: I solved the issue of having to pass store as the first parameter. Now I just need to somehow make getters behave correctly, which I don't know how to do. But I think if we combined this with the internals of direct-vuex, we could create the mappers directly when in createDirectStore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant