Last active
June 8, 2018 23:27
-
-
Save thehappycoder/5e86ff798517d7599c8af6b1abf2c574 to your computer and use it in GitHub Desktop.
Typesafe path function as an alternative to safe navigation operator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Need to use this special type so that keyof would work | |
export type TheType<T> = Required<NonNullable<T>> | |
export function path<P extends keyof TheType<T>, T>( | |
props: [P], | |
obj: T | |
): PropType<P, T> | |
export function path< | |
P extends keyof TheType<T>, | |
P2 extends keyof TheType<T>[P], | |
T | |
>(props: [P, P2], obj: T): PropType2<P, P2, T> | |
export function path< | |
P extends keyof TheType<T>, | |
P2 extends keyof TheType<T>[P], | |
P3 extends keyof Required<TheType<T>[P]>[P2], | |
T | |
>(props: [P, P2, P3], obj: T): PropType3<P, P2, P3, T> | |
export function path< | |
P extends keyof TheType<T>, | |
P2 extends keyof TheType<T>[P], | |
P3 extends keyof Required<TheType<T>[P]>[P2], | |
P4 extends keyof Required<Required<TheType<T>[P]>[P2]>[P3], | |
T | |
>(props: [P, P2, P3, P4], obj: T): PropType4<P, P2, P3, P4, T> | |
export function path< | |
P extends keyof TheType<T>, | |
P2 extends keyof TheType<T>[P], | |
P3 extends keyof Required<TheType<T>[P]>[P2], | |
P4 extends keyof Required<Required<TheType<T>[P]>[P2]>[P3], | |
T | |
>(props: [P] | [P, P2] | [P, P2, P3] | [P, P2, P3, P4], obj: T): any { | |
if (obj === null || obj === undefined) { | |
return obj | |
} | |
const [prop, ...tail] = props | |
const value = (obj as any)[prop] | |
if (value === null || value === undefined) { | |
return value | |
} | |
if (props.length === 1) { | |
return value | |
} | |
return path(tail as any, value) | |
} | |
export type PropType<P extends keyof TheType<T>, T> = undefined extends T | |
? TheType<T>[P] | undefined | |
: TheType<T>[P] | |
export type PropType2< | |
P extends keyof TheType<T>, | |
P2 extends keyof TheType<T>[P], | |
T | |
> = TheType<T>[P] extends object | |
? undefined extends T | |
? PropType<P2, TheType<T>[P]> | undefined | |
: PropType<P2, TheType<T>[P]> | |
: never | |
export type PropType3< | |
P extends keyof TheType<T>, | |
P2 extends keyof TheType<T>[P], | |
P3 extends keyof Required<TheType<T>[P]>[P2], | |
T | |
> = TheType<T>[P] extends object | |
? undefined extends T | |
? PropType2<P2, P3, TheType<T>[P]> | undefined | |
: PropType2<P2, P3, TheType<T>[P]> | |
: never | |
export type PropType4< | |
P extends keyof TheType<T>, | |
P2 extends keyof TheType<T>[P], | |
P3 extends keyof Required<TheType<T>[P]>[P2], | |
P4 extends keyof Required<Required<TheType<T>[P]>[P2]>[P3], | |
T | |
> = TheType<T>[P] extends object | |
? undefined extends T | |
? PropType3<P2, P3, P4, TheType<T>[P]> | undefined | |
: PropType3<P2, P3, P4, TheType<T>[P]> | |
: never |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment