Skip to content

Instantly share code, notes, and snippets.

@armedi
Created May 7, 2021 05:42
Show Gist options
  • Save armedi/97abd1e0eb02900e29eaa7e2b8a718ea to your computer and use it in GitHub Desktop.
Save armedi/97abd1e0eb02900e29eaa7e2b8a718ea to your computer and use it in GitHub Desktop.
set value for given object path with TypeScript
import { CamelCasedPropertiesDeep, Merge } from 'type-fest'
import { DeepRequired, MarkRequired } from 'ts-essentials'
// https://www.typescriptlang.org/play?ts=4.1.0-pr-40336-88&ssl=25&ssc=78&pln=1&pc=1#code/FAFwngDgpgBACgQxACwJIFsIBsA8AVAGhgGkowYoAPEKAOwBMBnGAazIHsAzGPAPhgC8wGCTIVqdJjEYgATgEtaAc2EwA-DwDapMAF1xNBswBKUAMbtZ9HDIXKiCWmF6qRGgD4wABgBIA3joAvgB0-ogoGNj42mS6RACilGZYAK70UDhsYFxaOnGsHNyOYJq6vPwAZNJyikqBXq4iMJ6+AWQh-onJaRlZOXgxekR9RU6lldV2dQ1NMABcMLRQAG5QsqoLS6uyANzAoJCw4WiYWABM+PwC8EgnUYQF2dx8zY-9ewfQNyiXgt9351+VEMUlstVeIx46n+kUBLwWkLwH3AX2OADUEKkMg84AZJMxjpcrqpccD8d5-IpOGtRGAOn4qTTTDJ6qoNDo8UY3s9GhpmSBOVJCQM8i5Zm5-hisdE8kR+WLxZsVmtGkrtht4ILmIjeVo4LpVYtlbt9ulkghZLBOClaGYQPJ2LQYEooCB8ERSRIucLygAKdgAIwAVgsHhBbgs4ABKSO3KUpbEe3gfCy0GQwQNB8wC65+VSceSyGQAOQQ6CgCwARAAReRQJTsSsEVRYBAlssVmCVgASCAAXk3VAgXQsAMwABmbIggsnYWbtjAWmkafkWHarpgQLHkICbMFTNQDKRAlkXMAAbAAOGCBKdNVe0dddgDCjpkSCge4PCiPJ6LCwARjOG87wNQIYDbfc3xAD4XRAf1g2zIhKxnOdzErKMdiAA
type PathImpl<T, Key extends keyof T> = Key extends string
? T[Key] extends Record<string, unknown>
?
| `${Key}.${PathImpl<T[Key], Exclude<keyof T[Key], keyof unknown[]>> &
string}`
| `${Key}.${Exclude<keyof T[Key], keyof unknown[]> & 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
type SetPathRequiredImpl1<T, P extends string> = P extends keyof T
? MarkRequired<T, P>
: P extends `${infer A}.${infer B}`
? A extends keyof T
? Merge<
MarkRequired<T, A>,
{
[K in A]: SetPathRequiredImpl1<MarkRequired<T, A>[K], B>
}
>
: never
: never
type SetPathRequired<
T,
P extends Path<DeepRequired<T>> & string
> = SetPathRequiredImpl1<T, P>
declare function set<
T,
P extends Path<DeepRequired<T>> & string,
V extends PathValue<DeepRequired<T>, P>
>(obj: T, path: P, value: V): SetPathRequired<T, P>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment