object.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /**
  2. * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. const hasOwnProperty = Object.prototype.hasOwnProperty;
  8. /** Assign to the object if a given property in update is undefined */
  9. export function assignIfUndefined<T>(to: Partial<T>, full: T): T {
  10. for (const k of Object.keys(full)) {
  11. if (!hasOwnProperty.call(full, k)) continue;
  12. if (typeof (to as any)[k] === 'undefined') {
  13. (to as any)[k] = (full as any)[k];
  14. }
  15. }
  16. return to as T;
  17. }
  18. /** Create new object if any property in "update" changes in "source". */
  19. export function shallowMerge2<T>(source: T, update: Partial<T>): T {
  20. // Adapted from LiteMol (https://github.com/dsehnal/LiteMol)
  21. let changed = false;
  22. for (let k of Object.keys(update)) {
  23. if (!hasOwnProperty.call(update, k)) continue;
  24. if ((update as any)[k] !== (source as any)[k]) {
  25. changed = true;
  26. break;
  27. }
  28. }
  29. if (!changed) return source;
  30. return Object.assign({}, source, update);
  31. }
  32. export function shallowEqual<T>(a: T, b: T) {
  33. if (!a) {
  34. if (!b) return true;
  35. return false;
  36. }
  37. if (!b) return false;
  38. let keys = Object.keys(a);
  39. if (Object.keys(b).length !== keys.length) return false;
  40. for (let k of keys) {
  41. if (!hasOwnProperty.call(a, k) || (a as any)[k] !== (b as any)[k]) return false;
  42. }
  43. return true;
  44. }
  45. export function shallowMerge<T>(source: T, ...rest: (Partial<T> | undefined)[]): T {
  46. return shallowMergeArray(source, rest);
  47. }
  48. export function shallowMergeArray<T>(source: T, rest: (Partial<T> | undefined)[]): T {
  49. // Adapted from LiteMol (https://github.com/dsehnal/LiteMol)
  50. let ret: any = source;
  51. for (let s = 0; s < rest.length; s++) {
  52. if (!rest[s]) continue;
  53. ret = shallowMerge2(source, rest[s] as T);
  54. if (ret !== source) {
  55. for (let i = s + 1; i < rest.length; i++) {
  56. ret = Object.assign(ret, rest[i]);
  57. }
  58. break;
  59. }
  60. }
  61. return ret;
  62. }
  63. /** Simple deep clone for number, boolean, string, null, undefined, object, array */
  64. export function deepClone<T>(source: T): T {
  65. if (null === source || 'object' !== typeof source) return source;
  66. if (source instanceof Array) {
  67. const copy: any[] = [];
  68. for (let i = 0, len = source.length; i < len; i++) {
  69. copy[i] = deepClone(source[i]);
  70. }
  71. return copy as any as T;
  72. }
  73. // `instanceof Object` does not find `Object.create(null)`
  74. if (typeof source === 'object' && !('prototype' in source)) {
  75. const copy: { [k: string]: any } = {};
  76. for (let k in source) {
  77. if (hasOwnProperty.call(source, k)) copy[k] = deepClone(source[k]);
  78. }
  79. return copy as any as T;
  80. }
  81. throw new Error(`Can't clone, type "${typeof source}" unsupported`);
  82. }
  83. export function mapObjectMap<T, S>(o: { [k: string]: T }, f: (v: T) => S): { [k: string]: S } {
  84. const ret: any = { };
  85. for (const k of Object.keys(o)) {
  86. ret[k] = f((o as any)[k]);
  87. }
  88. return ret;
  89. }
  90. export function objectForEach<T>(o: { [k: string]: T }, f: (v: T, k: string) => void) {
  91. if (!o) return;
  92. for (const k of Object.keys(o)) {
  93. f((o as any)[k], k);
  94. }
  95. }