@etsoo/shared 1.1.98 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -103,7 +103,9 @@ Array related utilities
103
103
  |---:|---|
104
104
  |differences|Array 1 items do not exist in Array 2 or reverse match|
105
105
  |max|Get max number item or number item property|
106
+ |maxItem|Get max field value item|
106
107
  |min|Get min number item or number item property|
108
+ |minItem|Get min field value item|
107
109
  |sum|Sum number items or number item properties|
108
110
  |toUnique|Make all items are unique|
109
111
 
@@ -44,8 +44,21 @@ test('Tests for max / min fields', () => {
44
44
  const items = [
45
45
  { id: 1, label: 'a', amount: 3.14 },
46
46
  { id: 2, label: 'b', amount: 4.54 },
47
- { id: 2, label: 'b', amount: 1.52 }
47
+ { id: 3, label: 'b', amount: 1.52 }
48
48
  ];
49
49
  expect(items.max('amount')).toBe(4.54);
50
50
  expect(items.min('amount')).toBe(1.52);
51
51
  });
52
+
53
+ test('Tests for maxItem / minItem', () => {
54
+ const items = [
55
+ { id: 1, label: 'a', amount: 3.14 },
56
+ { id: 2, label: 'b', amount: 4.54 },
57
+ { id: 3, label: 'b', amount: 1.52 }
58
+ ];
59
+ expect(items.maxItem('amount')?.id).toBe(2);
60
+ expect(items.minItem('amount')?.id).toBe(3);
61
+
62
+ const emptyItems: { id: string; amount: number }[] = [];
63
+ expect(emptyItems.maxItem('amount')).toBeUndefined();
64
+ });
@@ -12,11 +12,21 @@ declare global {
12
12
  * @param field Object field to calculate
13
13
  */
14
14
  max(...field: T extends number ? [undefined?] : T extends object ? [DataTypes.Keys<T, number>] : [never]): number;
15
+ /**
16
+ * Get max field value item
17
+ * @param field Object field to calculate
18
+ */
19
+ maxItem(field: T extends object ? DataTypes.Keys<T, number> : never): T | undefined;
15
20
  /**
16
21
  * Get min number item or number item property
17
22
  * @param field Object field to calculate
18
23
  */
19
24
  min(...field: T extends number ? [undefined?] : T extends object ? [DataTypes.Keys<T, number>] : [never]): number;
25
+ /**
26
+ * Get min field value item
27
+ * @param field Object field to calculate
28
+ */
29
+ minItem(field: T extends object ? DataTypes.Keys<T, number> : never): T | undefined;
20
30
  /**
21
31
  * Sum number items or number item properties
22
32
  * @param field Object field to calculate
@@ -25,12 +25,22 @@ Array.prototype.max = function (field) {
25
25
  }
26
26
  return Math.max(...this.map((item) => item[field]));
27
27
  };
28
+ Array.prototype.maxItem = function (field) {
29
+ if (this.length === 0)
30
+ return undefined;
31
+ return this.reduce((prev, curr) => prev[field] > curr[field] ? prev : curr);
32
+ };
28
33
  Array.prototype.min = function (field) {
29
34
  if (field == null) {
30
35
  return Math.min(...this);
31
36
  }
32
37
  return Math.min(...this.map((item) => item[field]));
33
38
  };
39
+ Array.prototype.minItem = function (field) {
40
+ if (this.length === 0)
41
+ return undefined;
42
+ return this.reduce((prev, curr) => prev[field] < curr[field] ? prev : curr);
43
+ };
34
44
  Array.prototype.sum = function (field) {
35
45
  if (field == null) {
36
46
  return this.reduce((total, num) => total + num, 0);
@@ -19,6 +19,8 @@ export interface TimeSpan {
19
19
  totalMonths: number;
20
20
  totalYears: number;
21
21
  }
22
+ type DateType = Date | string | null | undefined;
23
+ type DateReturn<T extends DateType, R> = T extends Date ? R : R | undefined;
22
24
  export declare namespace DateUtils {
23
25
  /**
24
26
  * Day format, YYYY-MM-DD
@@ -43,13 +45,13 @@ export declare namespace DateUtils {
43
45
  * @param options Options
44
46
  * @param timeZone Time zone
45
47
  */
46
- function format(input?: Date | string, locale?: string | string[], options?: FormatOptions, timeZone?: string): string | undefined;
48
+ function format<T extends DateType>(input: T, locale?: string | string[], options?: FormatOptions, timeZone?: string): DateReturn<T, string>;
47
49
  /**
48
50
  * Format to 'yyyy-MM-dd' or 'yyyy-MM-ddThh:mm:ss, especially used for date input min/max property
49
51
  * @param date Input date
50
52
  * @param hasSecondOrType 'undefined' for date only, 'false' for hour:minute only, 'true' for all, or input field type
51
53
  */
52
- function formatForInput(date?: Date | string | null, hasSecondOrType?: boolean | string): string | undefined;
54
+ function formatForInput<T extends DateType>(date: T, hasSecondOrType?: boolean | string): DateReturn<T, string>;
53
55
  /**
54
56
  * Get month's days
55
57
  * @param year Year
@@ -75,7 +77,7 @@ export declare namespace DateUtils {
75
77
  * @param input Input string
76
78
  * @returns Date
77
79
  */
78
- function parse(input?: Date | string | null): Date | undefined;
80
+ function parse<T extends DateType>(input: T): DateReturn<T, Date>;
79
81
  /**
80
82
  * Two dates are in the same day
81
83
  * @param d1 First date
@@ -91,3 +93,4 @@ export declare namespace DateUtils {
91
93
  */
92
94
  function sameMonth(d1?: Date | string | null, d2?: Date | string | null): boolean;
93
95
  }
96
+ export {};
@@ -101,8 +101,7 @@ var DateUtils;
101
101
  if (date == null || date === '')
102
102
  return undefined;
103
103
  // Parse string as date
104
- if (typeof date === 'string')
105
- date = new Date(date);
104
+ const dt = typeof date === 'string' ? new Date(date) : date;
106
105
  const hasSecond = typeof hasSecondOrType === 'string'
107
106
  ? hasSecondOrType === 'date'
108
107
  ? undefined
@@ -110,20 +109,20 @@ var DateUtils;
110
109
  : hasSecondOrType;
111
110
  // Parts
112
111
  const parts = [
113
- date.getFullYear(),
114
- (date.getMonth() + 1).toString().padStart(2, '0'),
115
- date.getDate().toString().padStart(2, '0')
112
+ dt.getFullYear(),
113
+ (dt.getMonth() + 1).toString().padStart(2, '0'),
114
+ dt.getDate().toString().padStart(2, '0')
116
115
  ];
117
116
  // Date
118
117
  const d = parts.join('-');
119
118
  if (hasSecond == null)
120
119
  return d;
121
120
  const hm = [
122
- date.getHours().toString().padStart(2, '0'),
123
- date.getMinutes().toString().padStart(2, '0')
121
+ dt.getHours().toString().padStart(2, '0'),
122
+ dt.getMinutes().toString().padStart(2, '0')
124
123
  ];
125
124
  if (hasSecond)
126
- hm.push(date.getSeconds().toString().padStart(2, '0'));
125
+ hm.push(dt.getSeconds().toString().padStart(2, '0'));
127
126
  return `${d}T${hm.join(':')}`;
128
127
  }
129
128
  DateUtils.formatForInput = formatForInput;
@@ -12,11 +12,21 @@ declare global {
12
12
  * @param field Object field to calculate
13
13
  */
14
14
  max(...field: T extends number ? [undefined?] : T extends object ? [DataTypes.Keys<T, number>] : [never]): number;
15
+ /**
16
+ * Get max field value item
17
+ * @param field Object field to calculate
18
+ */
19
+ maxItem(field: T extends object ? DataTypes.Keys<T, number> : never): T | undefined;
15
20
  /**
16
21
  * Get min number item or number item property
17
22
  * @param field Object field to calculate
18
23
  */
19
24
  min(...field: T extends number ? [undefined?] : T extends object ? [DataTypes.Keys<T, number>] : [never]): number;
25
+ /**
26
+ * Get min field value item
27
+ * @param field Object field to calculate
28
+ */
29
+ minItem(field: T extends object ? DataTypes.Keys<T, number> : never): T | undefined;
20
30
  /**
21
31
  * Sum number items or number item properties
22
32
  * @param field Object field to calculate
@@ -19,12 +19,22 @@ Array.prototype.max = function (field) {
19
19
  }
20
20
  return Math.max(...this.map((item) => item[field]));
21
21
  };
22
+ Array.prototype.maxItem = function (field) {
23
+ if (this.length === 0)
24
+ return undefined;
25
+ return this.reduce((prev, curr) => prev[field] > curr[field] ? prev : curr);
26
+ };
22
27
  Array.prototype.min = function (field) {
23
28
  if (field == null) {
24
29
  return Math.min(...this);
25
30
  }
26
31
  return Math.min(...this.map((item) => item[field]));
27
32
  };
33
+ Array.prototype.minItem = function (field) {
34
+ if (this.length === 0)
35
+ return undefined;
36
+ return this.reduce((prev, curr) => prev[field] < curr[field] ? prev : curr);
37
+ };
28
38
  Array.prototype.sum = function (field) {
29
39
  if (field == null) {
30
40
  return this.reduce((total, num) => total + num, 0);
@@ -19,6 +19,8 @@ export interface TimeSpan {
19
19
  totalMonths: number;
20
20
  totalYears: number;
21
21
  }
22
+ type DateType = Date | string | null | undefined;
23
+ type DateReturn<T extends DateType, R> = T extends Date ? R : R | undefined;
22
24
  export declare namespace DateUtils {
23
25
  /**
24
26
  * Day format, YYYY-MM-DD
@@ -43,13 +45,13 @@ export declare namespace DateUtils {
43
45
  * @param options Options
44
46
  * @param timeZone Time zone
45
47
  */
46
- function format(input?: Date | string, locale?: string | string[], options?: FormatOptions, timeZone?: string): string | undefined;
48
+ function format<T extends DateType>(input: T, locale?: string | string[], options?: FormatOptions, timeZone?: string): DateReturn<T, string>;
47
49
  /**
48
50
  * Format to 'yyyy-MM-dd' or 'yyyy-MM-ddThh:mm:ss, especially used for date input min/max property
49
51
  * @param date Input date
50
52
  * @param hasSecondOrType 'undefined' for date only, 'false' for hour:minute only, 'true' for all, or input field type
51
53
  */
52
- function formatForInput(date?: Date | string | null, hasSecondOrType?: boolean | string): string | undefined;
54
+ function formatForInput<T extends DateType>(date: T, hasSecondOrType?: boolean | string): DateReturn<T, string>;
53
55
  /**
54
56
  * Get month's days
55
57
  * @param year Year
@@ -75,7 +77,7 @@ export declare namespace DateUtils {
75
77
  * @param input Input string
76
78
  * @returns Date
77
79
  */
78
- function parse(input?: Date | string | null): Date | undefined;
80
+ function parse<T extends DateType>(input: T): DateReturn<T, Date>;
79
81
  /**
80
82
  * Two dates are in the same day
81
83
  * @param d1 First date
@@ -91,3 +93,4 @@ export declare namespace DateUtils {
91
93
  */
92
94
  function sameMonth(d1?: Date | string | null, d2?: Date | string | null): boolean;
93
95
  }
96
+ export {};
@@ -98,8 +98,7 @@ export var DateUtils;
98
98
  if (date == null || date === '')
99
99
  return undefined;
100
100
  // Parse string as date
101
- if (typeof date === 'string')
102
- date = new Date(date);
101
+ const dt = typeof date === 'string' ? new Date(date) : date;
103
102
  const hasSecond = typeof hasSecondOrType === 'string'
104
103
  ? hasSecondOrType === 'date'
105
104
  ? undefined
@@ -107,20 +106,20 @@ export var DateUtils;
107
106
  : hasSecondOrType;
108
107
  // Parts
109
108
  const parts = [
110
- date.getFullYear(),
111
- (date.getMonth() + 1).toString().padStart(2, '0'),
112
- date.getDate().toString().padStart(2, '0')
109
+ dt.getFullYear(),
110
+ (dt.getMonth() + 1).toString().padStart(2, '0'),
111
+ dt.getDate().toString().padStart(2, '0')
113
112
  ];
114
113
  // Date
115
114
  const d = parts.join('-');
116
115
  if (hasSecond == null)
117
116
  return d;
118
117
  const hm = [
119
- date.getHours().toString().padStart(2, '0'),
120
- date.getMinutes().toString().padStart(2, '0')
118
+ dt.getHours().toString().padStart(2, '0'),
119
+ dt.getMinutes().toString().padStart(2, '0')
121
120
  ];
122
121
  if (hasSecond)
123
- hm.push(date.getSeconds().toString().padStart(2, '0'));
122
+ hm.push(dt.getSeconds().toString().padStart(2, '0'));
124
123
  return `${d}T${hm.join(':')}`;
125
124
  }
126
125
  DateUtils.formatForInput = formatForInput;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/shared",
3
- "version": "1.1.98",
3
+ "version": "1.2.0",
4
4
  "description": "TypeScript shared utilities and functions",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -59,7 +59,7 @@
59
59
  "jest": "^29.5.0",
60
60
  "jest-environment-jsdom": "^29.5.0",
61
61
  "ts-jest": "^29.1.0",
62
- "typescript": "^5.0.3"
62
+ "typescript": "^5.0.4"
63
63
  },
64
64
  "dependencies": {
65
65
  "lodash.isequal": "^4.5.0"
package/src/ArrayUtils.ts CHANGED
@@ -22,6 +22,14 @@ declare global {
22
22
  : [never]
23
23
  ): number;
24
24
 
25
+ /**
26
+ * Get max field value item
27
+ * @param field Object field to calculate
28
+ */
29
+ maxItem(
30
+ field: T extends object ? DataTypes.Keys<T, number> : never
31
+ ): T | undefined;
32
+
25
33
  /**
26
34
  * Get min number item or number item property
27
35
  * @param field Object field to calculate
@@ -34,6 +42,14 @@ declare global {
34
42
  : [never]
35
43
  ): number;
36
44
 
45
+ /**
46
+ * Get min field value item
47
+ * @param field Object field to calculate
48
+ */
49
+ minItem(
50
+ field: T extends object ? DataTypes.Keys<T, number> : never
51
+ ): T | undefined;
52
+
37
53
  /**
38
54
  * Sum number items or number item properties
39
55
  * @param field Object field to calculate
@@ -85,6 +101,17 @@ Array.prototype.max = function <T>(
85
101
  return Math.max(...this.map((item) => item[field] as number));
86
102
  };
87
103
 
104
+ Array.prototype.maxItem = function <T>(
105
+ this: Array<T>,
106
+ field: T extends object ? DataTypes.Keys<T, number> : never
107
+ ) {
108
+ if (this.length === 0) return undefined;
109
+
110
+ return this.reduce((prev, curr) =>
111
+ prev[field] > curr[field] ? prev : curr
112
+ );
113
+ };
114
+
88
115
  Array.prototype.min = function <T>(
89
116
  this: Array<T>,
90
117
  field: T extends object ? DataTypes.Keys<T, number> : undefined
@@ -96,6 +123,17 @@ Array.prototype.min = function <T>(
96
123
  return Math.min(...this.map((item) => item[field] as number));
97
124
  };
98
125
 
126
+ Array.prototype.minItem = function <T>(
127
+ this: Array<T>,
128
+ field: T extends object ? DataTypes.Keys<T, number> : never
129
+ ) {
130
+ if (this.length === 0) return undefined;
131
+
132
+ return this.reduce((prev, curr) =>
133
+ prev[field] < curr[field] ? prev : curr
134
+ );
135
+ };
136
+
99
137
  Array.prototype.sum = function <T>(
100
138
  this: Array<T>,
101
139
  field: T extends object ? DataTypes.Keys<T, number> : undefined
package/src/DateUtils.ts CHANGED
@@ -63,6 +63,10 @@ export interface TimeSpan {
63
63
  totalYears: number;
64
64
  }
65
65
 
66
+ type DateType = Date | string | null | undefined;
67
+
68
+ type DateReturn<T extends DateType, R> = T extends Date ? R : R | undefined;
69
+
66
70
  export namespace DateUtils {
67
71
  /**
68
72
  * Day format, YYYY-MM-DD
@@ -103,17 +107,17 @@ export namespace DateUtils {
103
107
  * @param options Options
104
108
  * @param timeZone Time zone
105
109
  */
106
- export function format(
107
- input?: Date | string,
110
+ export function format<T extends DateType>(
111
+ input: T,
108
112
  locale?: string | string[],
109
113
  options?: FormatOptions,
110
114
  timeZone?: string
111
- ) {
115
+ ): DateReturn<T, string> {
112
116
  // Parse
113
117
  const parsed = parse(input);
114
118
 
115
119
  // Null case
116
- if (parsed == null) return undefined;
120
+ if (parsed == null) return <DateReturn<T, string>>undefined;
117
121
 
118
122
  // Default options
119
123
  options ??= DayFormat;
@@ -149,15 +153,16 @@ export namespace DateUtils {
149
153
  * @param date Input date
150
154
  * @param hasSecondOrType 'undefined' for date only, 'false' for hour:minute only, 'true' for all, or input field type
151
155
  */
152
- export function formatForInput(
153
- date?: Date | string | null,
156
+ export function formatForInput<T extends DateType>(
157
+ date: T,
154
158
  hasSecondOrType?: boolean | string
155
- ) {
159
+ ): DateReturn<T, string> {
156
160
  // Return when null
157
- if (date == null || date === '') return undefined;
161
+ if (date == null || date === '')
162
+ return <DateReturn<T, string>>undefined;
158
163
 
159
164
  // Parse string as date
160
- if (typeof date === 'string') date = new Date(date);
165
+ const dt: Date = typeof date === 'string' ? new Date(date) : date;
161
166
 
162
167
  const hasSecond =
163
168
  typeof hasSecondOrType === 'string'
@@ -168,9 +173,9 @@ export namespace DateUtils {
168
173
 
169
174
  // Parts
170
175
  const parts = [
171
- date.getFullYear(),
172
- (date.getMonth() + 1).toString().padStart(2, '0'),
173
- date.getDate().toString().padStart(2, '0')
176
+ dt.getFullYear(),
177
+ (dt.getMonth() + 1).toString().padStart(2, '0'),
178
+ dt.getDate().toString().padStart(2, '0')
174
179
  ];
175
180
 
176
181
  // Date
@@ -178,10 +183,10 @@ export namespace DateUtils {
178
183
  if (hasSecond == null) return d;
179
184
 
180
185
  const hm = [
181
- date.getHours().toString().padStart(2, '0'),
182
- date.getMinutes().toString().padStart(2, '0')
186
+ dt.getHours().toString().padStart(2, '0'),
187
+ dt.getMinutes().toString().padStart(2, '0')
183
188
  ];
184
- if (hasSecond) hm.push(date.getSeconds().toString().padStart(2, '0'));
189
+ if (hasSecond) hm.push(dt.getSeconds().toString().padStart(2, '0'));
185
190
  return `${d}T${hm.join(':')}`;
186
191
  }
187
192
 
@@ -235,17 +240,17 @@ export namespace DateUtils {
235
240
  * @param input Input string
236
241
  * @returns Date
237
242
  */
238
- export function parse(input?: Date | string | null) {
239
- if (input == null) return undefined;
243
+ export function parse<T extends DateType>(input: T): DateReturn<T, Date> {
244
+ if (input == null) return <DateReturn<T, Date>>undefined;
240
245
  if (typeof input === 'string') {
241
246
  const f = input[0];
242
247
  if (f >= '0' && f <= '9' && /[-\/\s]/g.test(input)) {
243
248
  const n = Date.parse(input);
244
249
  if (!isNaN(n)) return new Date(n);
245
250
  }
246
- return undefined;
251
+ return <DateReturn<T, Date>>undefined;
247
252
  }
248
- return input;
253
+ return <Date>input;
249
254
  }
250
255
 
251
256
  /**