Created
September 24, 2024 10:08
-
-
Save binjospookie/77f272e7f0fe1869d38a79b50ea8fb4c to your computer and use it in GitHub Desktop.
hook
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable @typescript-eslint/no-explicit-any, functional/immutable-data, no-restricted-syntax */ | |
import { type Store, type StoreValue, useStoreMap } from '@grlt/vendors/state'; | |
import { mergeDeepRight, notEquals } from '../../../helpers/helpers'; | |
import type { NonEmptyArray, Paths } from '../../../types/types'; | |
import { useStableKeys } from '../useStableKeys'; | |
type GetByPath<T, Path extends string> = Path extends `${infer K}.${infer Rest}` | |
? K extends keyof T | |
? { [Key in K]: GetByPath<T[K], Rest> } | |
: never | |
: Path extends keyof T | |
? { [Key in Path]: T[Path] } | |
: never; | |
type MergeObjects<T> = (T extends any ? (k: T) => void : never) extends (k: infer I) => void ? I : never; | |
type ExtractFromState<T, Paths extends string[]> = MergeObjects< | |
{ | |
[P in Paths[number]]: GetByPath<T, P>; | |
}[Paths[number]] | |
>; | |
const getObjectByPath = <T extends object, P extends Paths<T>>(obj: T, path: P) => { | |
const keys = path.split('.'); | |
let current = obj; | |
const result = {}; | |
let temp = result; | |
for (let i = 0; i < keys.length - 1; i++) { | |
// @ts-expect-error but sooo fast | |
temp[keys[i]] = {}; | |
// @ts-expect-error but sooo fast | |
temp = temp[keys[i]]; | |
// @ts-expect-error but sooo fast | |
current = current[keys[i]]; | |
} | |
// @ts-expect-error but sooo fast | |
temp[keys[keys.length - 1]] = current[keys[keys.length - 1]]; | |
return result; | |
}; | |
const createHookWithStoreGetter = <S extends Store<any>>($kv: S) => { | |
type State = StoreValue<S>; | |
type PathList = NonEmptyArray<Paths<State>>; | |
type Config<T extends PathList> = { | |
fn: (_: ExtractFromState<State, T>) => any; | |
keys: [any] | readonly any[] | any[]; | |
}; | |
type ConfigShort<T extends PathList> = (_: ExtractFromState<State, T>) => any; | |
function useKv<P extends PathList>(paths: P): ExtractFromState<State, P>; | |
function useKv<P extends PathList, C extends Config<P>>(paths: P, config: C): ReturnType<(typeof config)['fn']>; | |
function useKv<P extends PathList, C extends ConfigShort<P>>(paths: P, config: C): ReturnType<typeof config>; | |
// eslint-disable-next-line no-restricted-syntax | |
function useKv<P extends PathList, C extends Config<P> | ConfigShort<P> | undefined>(paths: P, config?: C) { | |
// @ts-expect-error leave me alone | |
const memoizedPaths = useStableKeys([...paths, ...(config?.keys ?? [])]); | |
return useStoreMap({ | |
store: $kv, | |
fn: (x) => { | |
const res = paths.reduce( | |
(result, path) => mergeDeepRight(result, getObjectByPath(x, path)), | |
{}, | |
) as ExtractFromState<State, P>; | |
return config ? (typeof config === 'function' ? config(res) : config.fn(res)) : res; | |
}, | |
keys: [memoizedPaths], | |
updateFilter: notEquals, | |
}); | |
} | |
return useKv; | |
}; | |
export { createHookWithStoreGetter }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment