I need help on transforming some challenging TS inspired pseudo code I wrote on paper to concrete TS.
type F<T, [x, ...r] extends ReadonlyArray<ReadonlyArray<keyof T>> =
Pick<T, ItemOf<X>> | F<T, R>;
// other approach explored
type F<T, U> =
U extends readonly [infer X, ...infer R] ?
X extends ReadonlyArray<keyof T> ?
Pick<T, ItemOf<X>> | F<T, R> : never : never;
For completeness sake, here's an ItemOf
definition which does what's expected, a "coproduct type" of literal strings ("a" | "b" | ...
) from a literal array, ready to be provided to Pick
:
type ItemOf<T> =
T extends ReadonlyArray<infer Item> ?
Item : never;
type Result = ItemOf<["a", "b"]> // successfully resolves to "a" | "b"
Is it possible to unwrap types like I'm trying to do ?
I know it might be to much ML inspired, but I'm interested in the features it might depend on to get this kind of type functor definition working on TS
Typical usage would be:
type Struct = {x: string, y: string, z: string};
const Fields = [["x", "y"], ["z"]] as const;
type Result = F<Struct, typeof Fields> // should resolve to {x: string, y: string} | {z: string};
Does this work for you?
type F<T, F extends readonly (readonly (keyof T)[])[]> =
{ [K in keyof F]: Pick<T, Extract<F[K], readonly (keyof T)[]>[number]> }[number]
type Result = F<Struct, typeof Fields>
// type Result = Pick<Struct, "x" | "y"> | Pick<Struct, "z">
I'm mapping over the array of keys and manipulating the results. Note that you can get the element of an array A
by looking up its number
property (A[number]
). If that works for you I can possibly expand the answer to explain. If not, please try to spell out what you're doing clearly (I had trouble following the text, sorry 😳), and maybe with multiple examples.
Hope that helps; good luck!