Skip to content

Instantly share code, notes, and snippets.

@typoerr
Created March 18, 2017 01:44
Show Gist options
  • Save typoerr/8bb28363e18c6690bbbb7bc169b9c7ec to your computer and use it in GitHub Desktop.
Save typoerr/8bb28363e18c6690bbbb7bc169b9c7ec to your computer and use it in GitHub Desktop.
immtable-updater
/* API */
export function getIn(src: object, path: _.Path) {
return _.parsePath(path).reduce((acc, k) => (acc as any)[k], src);
}
export function hasIn(src: object, path: _.Path) {
return _.existy(getIn(src, path));
}
export function setIn(src: object, path: _.Path, value: object) {
return _.rec(src, _.parsePath(path), value, 0);
}
export function updateIn(src: object, path: _.Path, updater: Function) {
return _.rec(src, _.parsePath(path), updater, 0);
}
export function deleteIn(src: object, path: _.Path) {
path = _.parsePath(path);
return updateIn(src, path.slice(0, -1), (o: any) => {
const target = path[path.length - 1];
return Array.isArray(o) ? o.filter((_, i) => i !== Number(target)) : _.omit(o, target);
});
}
/* utils */
export namespace _ {
export type Path = string | (string | number)[];
export const isArray = Array.isArray;
export function isPlainObject(obj: object) {
return obj instanceof Object && Object.getPrototypeOf(obj) === Object.prototype;
};
export function omit(src: any, key: string | number) {
const clone = { ...src };
delete clone[key];
return clone;
}
// 参考: https://github.com/debitoor/dot-prop-immutable
export function rec(src: any, path: _.Path, value: any, idx: number) {
let clone;
let key = path[idx];
if (path.length > idx) {
if (Array.isArray(src)) {
clone = src.slice();
} else {
clone = { ...src };
}
clone[key] = rec(clone[key] !== undefined ? clone[key] : {}, path, value, idx + 1);
return clone;
}
return (typeof value === 'function') ? value(src) : value;
};
export function parsePath(path: Path) {
return (typeof path === 'string') ? path.split('.') : [...path];
}
export function existy(v: any) {
return !(v === null || v === undefined);
}
// export namespace walk {
// export interface Walker {
// (info: Info): void;
// }
// export interface Info {
// key: string | number;
// value: any;
// current: any;
// index: number;
// }
// }
// export function walk(src: object, path: Path, walker: walk.Walker) {
// const len = path.length;
// let index = -1;
// let current: any = src;
// while (++index < len) {
// const key = path[index];
// const value = current ? current[key] : undefined;
// walker({ key, value, current, index });
// if (isPlainObject(value) || isArray(value)) {
// current = value;
// } else {
// current = undefined;
// }
// }
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment