Skip to content

Instantly share code, notes, and snippets.

@zenobiopereira
Last active February 26, 2024 20:08
Show Gist options
  • Save zenobiopereira/c006d9917c33ebf6cb31d598a9d5f9ea to your computer and use it in GitHub Desktop.
Save zenobiopereira/c006d9917c33ebf6cb31d598a9d5f9ea to your computer and use it in GitHub Desktop.
Type for an abstract function *get*.
// For the given type, it will return the union of all possible paths recursively or not.
// Tested in https://www.typescriptlang.org/play
// TS version - 3.7.5
type B = {
c: number,
d: { e: number }
};
type A = {
a: string,
b: B
} & B;
type X = { b: { c: { z: number }; d: number } };
// ---cut--- Only TS version >= 4 ---cut---
// type Path<T> = PathTree<T>[keyof PathTree<T>];
// type PathTree<T> = {
// [P in keyof T]: T[P] extends object
// ? [P, ...(Path<T[P]> extends [infer H, ...(infer T)] ? [H, ...T] : [])]
// : [P];
// };
// ---cut---
type Path<T> = PathTree<T>[keyof T];
type Cons<H, T> = T extends unknown[]
? ((h: H, ...t: T) => void) extends ((...r: infer R) => void)
? R
: never
: never;
type PathTree<T> = {
[P in keyof T]: T[P] extends object
? [P] | Cons<P, Path<T[P]>>
: [P]
};
type Assert<A, B extends A> = any
type successCases = [
Assert<Path<A>, ['a']>,
Assert<Path<A>, ['b']>,
Assert<Path<A>, ['b', 'c']>,
Assert<Path<A>, ['b', 'd']>,
Assert<Path<A>, ['b', 'd', 'e']>,
Assert<Path<A>, ['c']>,
Assert<Path<A>, ['d']>,
Assert<Path<A>, ['d', 'e']>,
Assert<(Path<A> extends string[] ? Path<A> : never) | (string & keyof A), ['d', 'e']>
]
type errorCases = [
// @ts-expect-error
Assert<Path<X>, ['b', 'd', 'z']>,
// @ts-expect-error
Assert<Path<B>, ['a', 'c']>,
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment