Skip to content

Instantly share code, notes, and snippets.

@Luiz-Monad
Last active November 6, 2021 01:34
Show Gist options
  • Select an option

  • Save Luiz-Monad/200d7075c42520f1d559496e4dc48ccf to your computer and use it in GitHub Desktop.

Select an option

Save Luiz-Monad/200d7075c42520f1d559496e4dc48ccf to your computer and use it in GitHub Desktop.
type flatten and access
type ElementType<A extends { [key: string]: A[keyof A] }> = A[string];
type DeepRequired<T> = T extends Object ? { [K in keyof T]-?: DeepRequired<T[K]> } : Required<NonNullable<T>>;
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
type FLeaf<T, N> = { leaf: T; name: N }
type FNode<T, N> = { node: T; name: N }
type Lift<T, K> =
T extends Array<any> ? FLeaf<T, K> :
T extends object ? FNode<T, K> :
FLeaf<T, K>
type Fold<T> = {
[K in keyof T & string]:
Lift<T[K], K>
}[keyof T & string];
type PropAccess<K extends string | null, P extends string> =
K extends null ? P : `${K}.${P}`;
type RecurseN<T, K extends string | null> =
T extends FLeaf<infer ST, infer SK> ? (SK extends string ?
Record<PropAccess<K, SK>, ST> : never) :
T extends FNode<infer ST, infer SK> ? (SK extends string ?
Record<PropAccess<K, SK>, ST> |
RecurseN<ST, PropAccess<K, SK>> : never) :
UnionToIntersection<RecurseN<Fold<T>, K>>
type PropNav<T> = keyof RecurseN<T, null>
type PropType<T, K extends keyof RecurseN<T, null>> = RecurseN<T, null>[K]
type A = {
0: 1
test: number
x: string[]
a: {
b: {
c: number
}
}
}
type Test0 = RecurseN<A, null>
type Test1 = PropNav<A>
type Test2 = PropType<A, 'a.b'>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment