-
Notifications
You must be signed in to change notification settings - Fork 154
/
Copy pathtypeUtils.ts
179 lines (161 loc) · 3.92 KB
/
typeUtils.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/**
* Returns true if the passed value is a record (object).
*
* @param value The value to check
*/
const isRecord = (
value: unknown
): value is Record<string | number, unknown> => {
return (
Object.prototype.toString.call(value) === '[object Object]' &&
!Object.is(value, null)
);
};
/**
* Check if a value is a string.
*
* @param value The value to check
*/
const isString = (value: unknown): value is string => {
return typeof value === 'string';
};
/**
* Check if a value is a number.
*
* @param value The value to check
*/
const isNumber = (value: unknown): value is number => {
return typeof value === 'number';
};
/**
* Check if a value is an integer number.
*
* @param value The value to check
*/
const isIntegerNumber = (value: unknown): value is number => {
return isNumber(value) && Number.isInteger(value);
};
/**
* Check if a value is truthy.
*
* @param value The value to check
*/
const isTruthy = (value: unknown): boolean => {
if (isString(value)) {
return value !== '';
} else if (isNumber(value)) {
return value !== 0;
} else if (typeof value === 'boolean') {
return value;
} else if (Array.isArray(value)) {
return value.length > 0;
} else if (isRecord(value)) {
return Object.keys(value).length > 0;
} else {
return false;
}
};
/**
* Check if a value is null.
*
* @param value The value to check
*/
const isNull = (value: unknown): value is null => {
return Object.is(value, null);
};
/**
* Check if a value is null or undefined.
*
* @param value The value to check
*/
const isNullOrUndefined = (value: unknown): value is null | undefined => {
return isNull(value) || Object.is(value, undefined);
};
/**
* Get the type of a value as a string.
*
* @param value The value to check
*/
const getType = (value: unknown): string => {
if (Array.isArray(value)) {
return 'array';
} else if (isRecord(value)) {
return 'object';
} else if (isString(value)) {
return 'string';
} else if (isNumber(value)) {
return 'number';
} else if (typeof value === 'boolean') {
return 'boolean';
} else if (isNull(value)) {
return 'null';
} else {
return 'unknown';
}
};
/**
* Compare two arrays for strict equality.
*
* @param left The left array to compare
* @param right The right array to compare
*/
const areArraysEqual = (left: unknown[], right: unknown[]): boolean => {
if (left.length !== right.length) {
return false;
}
return left.every((value, i) => isStrictEqual(value, right[i]));
};
/**
* Compare two records for strict equality.
*
* @param left The left record to compare
* @param right The right record to compare
*/
const areRecordsEqual = (
left: Record<string, unknown>,
right: Record<string, unknown>
): boolean => {
const leftKeys = Object.keys(left);
const rightKeys = Object.keys(right);
if (leftKeys.length !== rightKeys.length) {
return false;
}
return leftKeys.every((key) => isStrictEqual(left[key], right[key]));
};
/**
* Check if two unknown values are strictly equal.
*
* If the values are arrays, then each element is compared, regardless of
* order. If the values are objects, then each key and value from left
* is compared to the corresponding key and value from right. If the
* values are primitives, then they are compared using strict equality.
*
* @param left Left side of strict equality comparison
* @param right Right side of strict equality comparison
*/
const isStrictEqual = (left: unknown, right: unknown): boolean => {
if (left === right) {
return true;
}
if (typeof left !== typeof right) {
return false;
}
if (Array.isArray(left) && Array.isArray(right)) {
return areArraysEqual(left, right);
}
if (isRecord(left) && isRecord(right)) {
return areRecordsEqual(left, right);
}
return false;
};
export {
isRecord,
isString,
isNumber,
isIntegerNumber,
isTruthy,
isNull,
isNullOrUndefined,
getType,
isStrictEqual,
};