-
Notifications
You must be signed in to change notification settings - Fork 199
/
Copy pathobject.ts
94 lines (81 loc) · 2.39 KB
/
object.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
type InspectableObject = Record<string | number | symbol, unknown>;
function isObject(o: unknown): o is InspectableObject {
return Object.prototype.toString.call(o) === '[object Object]';
}
export function isPlainObject(o: unknown): o is InspectableObject {
if (!isObject(o)) {
return false;
}
// If has modified constructor
const ctor = o.constructor;
if (ctor === undefined) {
return true;
}
// If has modified prototype
const prot = ctor.prototype;
if (isObject(prot) === false) {
return false;
}
// If constructor does not have an Object-specific method
if (prot.hasOwnProperty('isPrototypeOf') === false) {
return false;
}
// Most likely a plain Object
return true;
}
// Slates deep equality function: https://github.com/ianstormtaylor/slate/blob/68aff89e892fe15a16314398ff052ade6068900b/packages/slate/src/utils/deep-equal.ts#L13
// We have to match slates deepEquals behavior to merge insert deltas in the same way slate does.
export function deepEquals(node: any, another: any): boolean {
// eslint-disable-next-line guard-for-in
for (const key in node) {
const a = node[key];
const b = another[key];
if (isPlainObject(a) && isPlainObject(b)) {
if (!deepEquals(a, b)) {
return false;
}
} else if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
} else if (a !== b) {
return false;
}
}
for (const key in another) {
if (node[key] === undefined && another[key] !== undefined) {
return false;
}
}
return true;
}
export function pick<
TObj extends Record<string, any>,
TKeys extends keyof TObj,
>(obj: TObj, ...keys: TKeys[]): Pick<TObj, TKeys> {
return Object.fromEntries(
Object.entries(obj).filter(([key]) => keys.includes(key as TKeys)),
) as Pick<TObj, TKeys>;
}
export function omit<
TObj extends Record<string, any>,
TKeys extends keyof TObj,
>(obj: TObj, ...keys: TKeys[]): Omit<TObj, TKeys> {
return Object.fromEntries(
Object.entries(obj).filter(([key]) => !keys.includes(key as TKeys)),
) as Omit<TObj, TKeys>;
}
export function omitNullEntries<TObj extends Record<string, any>>(
obj: TObj,
): {
[K in keyof TObj]: TObj[K] extends null ? never : K;
} {
return Object.fromEntries(
Object.entries(obj).filter(([, value]) => value !== null),
) as {
[K in keyof TObj]: TObj[K] extends null ? never : K;
};
}