Skip to content

Commit 9208393

Browse files
dreamorosiam29d
andauthored
improv(commons): expand type utils functions (#2189)
* improv(commons): expand type utils functions * Update packages/commons/tests/unit/typeUtils.test.ts Co-authored-by: Alexander Schueren <[email protected]> * chore: add number as record key type --------- Co-authored-by: Alexander Schueren <[email protected]>
1 parent ebe5eef commit 9208393

File tree

6 files changed

+527
-173
lines changed

6 files changed

+527
-173
lines changed

Diff for: packages/commons/package.json

+8
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
"default": "./lib/esm/index.js"
4141
}
4242
},
43+
"./typeutils": {
44+
"import": "./lib/esm/typeUtils.js",
45+
"require": "./lib/cjs/typeUtils.js"
46+
},
4347
"./utils/base64": {
4448
"import": "./lib/esm/fromBase64.js",
4549
"require": "./lib/cjs/fromBase64.js"
@@ -51,6 +55,10 @@
5155
},
5256
"typesVersions": {
5357
"*": {
58+
"typeutils": [
59+
"lib/cjs/typeUtils.d.ts",
60+
"lib/esm/typeUtils.d.ts"
61+
],
5462
"utils/base64": [
5563
"lib/cjs/fromBase64.d.ts",
5664
"lib/esm/fromBase64.d.ts"

Diff for: packages/commons/src/guards.ts

-52
This file was deleted.

Diff for: packages/commons/src/index.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
export { isRecord, isString, isTruthy, isNullOrUndefined } from './guards.js';
1+
export {
2+
isRecord,
3+
isString,
4+
isNumber,
5+
isIntegerNumber,
6+
isTruthy,
7+
isNull,
8+
isNullOrUndefined,
9+
getType,
10+
isStrictEqual,
11+
} from './typeUtils.js';
212
export { Utility } from './Utility.js';
313
export { EnvironmentVariablesService } from './config/EnvironmentVariablesService.js';
414
export { addUserAgentMiddleware, isSdkClient } from './awsSdkUtils.js';

Diff for: packages/commons/src/typeUtils.ts

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/**
2+
* Returns true if the passed value is a record (object).
3+
*
4+
* @param value The value to check
5+
*/
6+
const isRecord = (
7+
value: unknown
8+
): value is Record<string | number, unknown> => {
9+
return (
10+
Object.prototype.toString.call(value) === '[object Object]' &&
11+
!Object.is(value, null)
12+
);
13+
};
14+
15+
/**
16+
* Check if a value is a string.
17+
*
18+
* @param value The value to check
19+
*/
20+
const isString = (value: unknown): value is string => {
21+
return typeof value === 'string';
22+
};
23+
24+
/**
25+
* Check if a value is a number.
26+
*
27+
* @param value The value to check
28+
*/
29+
const isNumber = (value: unknown): value is number => {
30+
return typeof value === 'number';
31+
};
32+
33+
/**
34+
* Check if a value is an integer number.
35+
*
36+
* @param value The value to check
37+
*/
38+
const isIntegerNumber = (value: unknown): value is number => {
39+
return isNumber(value) && Number.isInteger(value);
40+
};
41+
42+
/**
43+
* Check if a value is truthy.
44+
*
45+
* @param value The value to check
46+
*/
47+
const isTruthy = (value: unknown): boolean => {
48+
if (isString(value)) {
49+
return value !== '';
50+
} else if (isNumber(value)) {
51+
return value !== 0;
52+
} else if (typeof value === 'boolean') {
53+
return value;
54+
} else if (Array.isArray(value)) {
55+
return value.length > 0;
56+
} else if (isRecord(value)) {
57+
return Object.keys(value).length > 0;
58+
} else {
59+
return false;
60+
}
61+
};
62+
63+
/**
64+
* Check if a value is null.
65+
*
66+
* @param value The value to check
67+
*/
68+
const isNull = (value: unknown): value is null => {
69+
return Object.is(value, null);
70+
};
71+
72+
/**
73+
* Check if a value is null or undefined.
74+
*
75+
* @param value The value to check
76+
*/
77+
const isNullOrUndefined = (value: unknown): value is null | undefined => {
78+
return isNull(value) || Object.is(value, undefined);
79+
};
80+
81+
/**
82+
* Get the type of a value as a string.
83+
*
84+
* @param value The value to check
85+
*/
86+
const getType = (value: unknown): string => {
87+
if (Array.isArray(value)) {
88+
return 'array';
89+
} else if (isRecord(value)) {
90+
return 'object';
91+
} else if (isString(value)) {
92+
return 'string';
93+
} else if (isNumber(value)) {
94+
return 'number';
95+
} else if (typeof value === 'boolean') {
96+
return 'boolean';
97+
} else if (isNull(value)) {
98+
return 'null';
99+
} else {
100+
return 'unknown';
101+
}
102+
};
103+
104+
/**
105+
* Compare two arrays for strict equality.
106+
*
107+
* @param left The left array to compare
108+
* @param right The right array to compare
109+
*/
110+
const areArraysEqual = (left: unknown[], right: unknown[]): boolean => {
111+
if (left.length !== right.length) {
112+
return false;
113+
}
114+
115+
return left.every((value, i) => isStrictEqual(value, right[i]));
116+
};
117+
118+
/**
119+
* Compare two records for strict equality.
120+
*
121+
* @param left The left record to compare
122+
* @param right The right record to compare
123+
*/
124+
const areRecordsEqual = (
125+
left: Record<string, unknown>,
126+
right: Record<string, unknown>
127+
): boolean => {
128+
const leftKeys = Object.keys(left);
129+
const rightKeys = Object.keys(right);
130+
131+
if (leftKeys.length !== rightKeys.length) {
132+
return false;
133+
}
134+
135+
return leftKeys.every((key) => isStrictEqual(left[key], right[key]));
136+
};
137+
138+
/**
139+
* Check if two unknown values are strictly equal.
140+
*
141+
* If the values are arrays, then each element is compared, regardless of
142+
* order. If the values are objects, then each key and value from left
143+
* is compared to the corresponding key and value from right. If the
144+
* values are primitives, then they are compared using strict equality.
145+
*
146+
* @param left Left side of strict equality comparison
147+
* @param right Right side of strict equality comparison
148+
*/
149+
const isStrictEqual = (left: unknown, right: unknown): boolean => {
150+
if (left === right) {
151+
return true;
152+
}
153+
154+
if (typeof left !== typeof right) {
155+
return false;
156+
}
157+
158+
if (Array.isArray(left) && Array.isArray(right)) {
159+
return areArraysEqual(left, right);
160+
}
161+
162+
if (isRecord(left) && isRecord(right)) {
163+
return areRecordsEqual(left, right);
164+
}
165+
166+
return false;
167+
};
168+
169+
export {
170+
isRecord,
171+
isString,
172+
isNumber,
173+
isIntegerNumber,
174+
isTruthy,
175+
isNull,
176+
isNullOrUndefined,
177+
getType,
178+
isStrictEqual,
179+
};

Diff for: packages/commons/tests/unit/guards.test.ts

-120
This file was deleted.

0 commit comments

Comments
 (0)