Skip to content

Instantly share code, notes, and snippets.

@VladSez
Last active February 13, 2023 13:55
Show Gist options
  • Save VladSez/abd140745687029373f664e68d6af13c to your computer and use it in GitHub Desktop.
Save VladSez/abd140745687029373f664e68d6af13c to your computer and use it in GitHub Desktop.
Typed get. Dot notation string type-safe
// https://tsplay.dev/WvaG4m
// Source: https://github.com/ghoullier/awesome-template-literal-types#dot-notation-string-type-safe
// alternative: https://github.com/g-makarov/dot-path-value
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;
type PathImpl2<T> = PathImpl<T, keyof T> | keyof T;
type Path<T> = PathImpl2<T> extends string | keyof T ? PathImpl2<T> : keyof T;
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;
declare function get<T, P extends Path<T>>(obj: T, path: P): PathValue<T, P>;
const object = {
firstName: "Diego",
lastName: "Haz",
age: 30,
projects: [
{ name: "Reakit", contributors: 68 },
{ name: "Constate", contributors: 12 },
]
} as const;
const lol = get(object, "projects.0");
// ^?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment