Open cefn opened 1 year ago
Here's an example manually-tested implementation...
import { createStructuredSelector } from "reselect";
export function createPicker<T, K extends keyof T>(
...keys: K[]
): (state: T) => Pick<T, K> {
const selectorEntries = keys.map((key) => [key, (state: T) => state[key]]);
const selector = createStructuredSelector<Pick<T, K>>(
Object.fromEntries(selectorEntries)
);
return (value: T) => {
return selector(value);
};
}
export function createGameStatePicker<K extends keyof GameState>(...keys: K[]) {
return createPicker<Immutable<GameState>, K>(...keys);
}
It's used a bit like this...
const selector = createGameStatePicker("guessedLetters", "wordToGuess");
export function HangmanWord(props: GameProps) {
const { gameStore } = props;
const { guessedLetters, wordToGuess } = useSelected(gameStore, selector);
Could wrap around https://www.npmjs.com/package/just-safe-get and adopt the typings of https://github.com/cefn/lauf/issues/180
Here's an example of a working inference of Path strings, and of their referents...
export type PathImpl<T, Key extends keyof T> = Key extends string
? T[Key] extends Record<string, any>
?
| `${Key}.${PathImpl<T[Key], Exclude<keyof T[Key], keyof any[]>> &
string}`
| `${Key}.${Exclude<keyof T[Key], keyof any[]> & string}`
: never
: never;
export type DescendantPath<T> = PathImpl<T, keyof T> | keyof T;
export type Path<T> = keyof T extends string
? DescendantPath<T> extends string | keyof T
? DescendantPath<T>
: keyof T
:never
export type PathValue<
T,
P extends Path<T>,
> = P extends `${infer Key}.${infer Rest}`
? Key extends keyof T
? Rest extends Path<T[Key]>
? PathValue<T[Key], Rest>
: never
: never
: P extends keyof T
? T[P]
: never;
const tree = {
grandparent:{
parent:{
child:{
hands:{
left:{
fingers:[0,1,2,3,4]
},
right:{
fingers:[0,1,2,3,4]
}
}
}
}
}
} as const;
const treePath: Path<typeof tree> = "grandparent.parent.child";
type PathReferent = PathValue<typeof tree, typeof treePath>
If the argument passed to useSelected is a list of state paths, it would be very useful if this could compose all the complex elements of a lazy selection.
So the following would return a well-typed lookup and only cause a React re-render when one of the specified paths had varied....
The useSelectedPaths call would be equivalent to something like this maybe...