Skip to content

Instantly share code, notes, and snippets.

@progapandist
Created February 14, 2021 19:53
Show Gist options
  • Save progapandist/9912666e927e40678f8793ff5c8df3a7 to your computer and use it in GitHub Desktop.
Save progapandist/9912666e927e40678f8793ff5c8df3a7 to your computer and use it in GitHub Desktop.
type NotObject<T> = T extends object ? never : T;
type IndexedFlat<T> = {
[key in string]: NotObject<T>;
};
type IndexedNested = {
[key in string]: object;
};
type Indexed<T = unknown> = IndexedFlat<T> | IndexedNested;
function isIndexedObject(obj: Indexed | unknown): obj is Indexed {
return typeof obj === "object";
}
function isString(str: unknown): str is String {
return typeof str === "string";
}
function set(
object: Indexed | unknown,
path: string,
value: unknown
): Indexed | unknown {
if (!isIndexedObject(object)) {
return object;
}
if (!isString(path)) {
throw new Error("path must be string");
}
let segments = path.split(".");
if (object[segments[0]]) {
object[segments[0]] = value;
}
let traversePath = (): Indexed => {
return segments.reduce((acc, val, idx, keys) => {
let next = keys[idx + 1];
if (next) {
keys.shift();
acc[val] = traversePath();
} else {
acc[val] = value;
}
return Object.fromEntries(Object.entries(acc).slice(0, 1));
}, {} as Indexed);
};
object = {...object, ...traversePath()};
return object;
}
console.log(set(3, "foo.bar", "baz")); // 3
console.log(
set({foo: 5}, "bar.baz.bla", 10) // { foo: 5, bar: { baz: 10 } }
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment