ts-data-forge 3.2.0 → 3.3.1
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 +45 -21
- package/dist/array/impl/array-utils-creation.d.mts +116 -0
- package/dist/array/impl/array-utils-creation.d.mts.map +1 -0
- package/dist/array/impl/array-utils-creation.mjs +110 -0
- package/dist/array/impl/array-utils-creation.mjs.map +1 -0
- package/dist/array/impl/array-utils-element-access.d.mts +61 -0
- package/dist/array/impl/array-utils-element-access.d.mts.map +1 -0
- package/dist/array/impl/array-utils-element-access.mjs +66 -0
- package/dist/array/impl/array-utils-element-access.mjs.map +1 -0
- package/dist/array/impl/array-utils-iterators.d.mts +59 -0
- package/dist/array/impl/array-utils-iterators.d.mts.map +1 -0
- package/dist/array/impl/array-utils-iterators.mjs +104 -0
- package/dist/array/impl/array-utils-iterators.mjs.map +1 -0
- package/dist/array/impl/array-utils-modification.d.mts +154 -0
- package/dist/array/impl/array-utils-modification.d.mts.map +1 -0
- package/dist/array/impl/array-utils-modification.mjs +139 -0
- package/dist/array/impl/array-utils-modification.mjs.map +1 -0
- package/dist/array/impl/array-utils-reducing-value.d.mts +214 -0
- package/dist/array/impl/array-utils-reducing-value.d.mts.map +1 -0
- package/dist/array/impl/array-utils-reducing-value.mjs +160 -0
- package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -0
- package/dist/array/impl/array-utils-search.d.mts +179 -0
- package/dist/array/impl/array-utils-search.d.mts.map +1 -0
- package/dist/array/impl/array-utils-search.mjs +153 -0
- package/dist/array/impl/array-utils-search.mjs.map +1 -0
- package/dist/array/impl/array-utils-set-op.d.mts +100 -0
- package/dist/array/impl/array-utils-set-op.d.mts.map +1 -0
- package/dist/array/impl/array-utils-set-op.mjs +137 -0
- package/dist/array/impl/array-utils-set-op.mjs.map +1 -0
- package/dist/array/impl/array-utils-size.d.mts +24 -0
- package/dist/array/impl/array-utils-size.d.mts.map +1 -0
- package/dist/array/impl/array-utils-size.mjs +28 -0
- package/dist/array/impl/array-utils-size.mjs.map +1 -0
- package/dist/array/impl/array-utils-slice-clamped.d.mts +18 -0
- package/dist/array/impl/array-utils-slice-clamped.d.mts.map +1 -0
- package/dist/array/impl/array-utils-slice-clamped.mjs +49 -0
- package/dist/array/impl/array-utils-slice-clamped.mjs.map +1 -0
- package/dist/array/impl/array-utils-slicing.d.mts +120 -0
- package/dist/array/impl/array-utils-slicing.d.mts.map +1 -0
- package/dist/array/impl/array-utils-slicing.mjs +140 -0
- package/dist/array/impl/array-utils-slicing.mjs.map +1 -0
- package/dist/array/impl/array-utils-transformation.d.mts +348 -0
- package/dist/array/impl/array-utils-transformation.d.mts.map +1 -0
- package/dist/array/impl/array-utils-transformation.mjs +331 -0
- package/dist/array/impl/array-utils-transformation.mjs.map +1 -0
- package/dist/array/impl/array-utils-validation.d.mts +149 -0
- package/dist/array/impl/array-utils-validation.d.mts.map +1 -0
- package/dist/array/impl/array-utils-validation.mjs +166 -0
- package/dist/array/impl/array-utils-validation.mjs.map +1 -0
- package/dist/array/impl/index.d.mts +13 -0
- package/dist/array/impl/index.d.mts.map +1 -0
- package/dist/array/impl/index.mjs +13 -0
- package/dist/array/impl/index.mjs.map +1 -0
- package/dist/array/index.d.mts +1 -1
- package/dist/array/index.d.mts.map +1 -1
- package/dist/array/index.mjs +2 -1
- package/dist/array/index.mjs.map +1 -1
- package/dist/collections/imap-mapped.d.mts +83 -253
- package/dist/collections/imap-mapped.d.mts.map +1 -1
- package/dist/collections/imap-mapped.mjs +33 -164
- package/dist/collections/imap-mapped.mjs.map +1 -1
- package/dist/collections/imap.d.mts +436 -163
- package/dist/collections/imap.d.mts.map +1 -1
- package/dist/collections/imap.mjs +74 -94
- package/dist/collections/imap.mjs.map +1 -1
- package/dist/collections/iset-mapped.d.mts +828 -345
- package/dist/collections/iset-mapped.d.mts.map +1 -1
- package/dist/collections/iset-mapped.mjs +200 -242
- package/dist/collections/iset-mapped.mjs.map +1 -1
- package/dist/collections/iset.d.mts +397 -205
- package/dist/collections/iset.d.mts.map +1 -1
- package/dist/collections/iset.mjs +102 -184
- package/dist/collections/iset.mjs.map +1 -1
- package/dist/collections/queue.d.mts +155 -135
- package/dist/collections/queue.d.mts.map +1 -1
- package/dist/collections/queue.mjs +55 -156
- package/dist/collections/queue.mjs.map +1 -1
- package/dist/collections/stack.d.mts +154 -154
- package/dist/collections/stack.d.mts.map +1 -1
- package/dist/collections/stack.mjs +54 -203
- package/dist/collections/stack.mjs.map +1 -1
- package/dist/entry-point.d.mts +3 -0
- package/dist/entry-point.d.mts.map +1 -0
- package/dist/entry-point.mjs +62 -0
- package/dist/entry-point.mjs.map +1 -0
- package/dist/expect-type.d.mts +43 -172
- package/dist/expect-type.d.mts.map +1 -1
- package/dist/expect-type.mjs +43 -172
- package/dist/expect-type.mjs.map +1 -1
- package/dist/functional/match.d.mts +35 -140
- package/dist/functional/match.d.mts.map +1 -1
- package/dist/functional/match.mjs.map +1 -1
- package/dist/functional/optional.d.mts +282 -160
- package/dist/functional/optional.d.mts.map +1 -1
- package/dist/functional/optional.mjs +131 -71
- package/dist/functional/optional.mjs.map +1 -1
- package/dist/functional/pipe.d.mts +59 -113
- package/dist/functional/pipe.d.mts.map +1 -1
- package/dist/functional/pipe.mjs.map +1 -1
- package/dist/functional/result.d.mts +433 -332
- package/dist/functional/result.d.mts.map +1 -1
- package/dist/functional/result.mjs +233 -239
- package/dist/functional/result.mjs.map +1 -1
- package/dist/globals.d.mts +12 -5
- package/dist/guard/has-key.d.mts +23 -74
- package/dist/guard/has-key.d.mts.map +1 -1
- package/dist/guard/has-key.mjs +23 -74
- package/dist/guard/has-key.mjs.map +1 -1
- package/dist/guard/is-non-empty-string.d.mts +20 -87
- package/dist/guard/is-non-empty-string.d.mts.map +1 -1
- package/dist/guard/is-non-empty-string.mjs +20 -87
- package/dist/guard/is-non-empty-string.mjs.map +1 -1
- package/dist/guard/is-non-null-object.d.mts +14 -84
- package/dist/guard/is-non-null-object.d.mts.map +1 -1
- package/dist/guard/is-non-null-object.mjs +14 -84
- package/dist/guard/is-non-null-object.mjs.map +1 -1
- package/dist/guard/is-primitive.d.mts +13 -126
- package/dist/guard/is-primitive.d.mts.map +1 -1
- package/dist/guard/is-primitive.mjs +13 -126
- package/dist/guard/is-primitive.mjs.map +1 -1
- package/dist/guard/is-record.d.mts +21 -132
- package/dist/guard/is-record.d.mts.map +1 -1
- package/dist/guard/is-record.mjs +21 -132
- package/dist/guard/is-record.mjs.map +1 -1
- package/dist/guard/is-type.d.mts +201 -238
- package/dist/guard/is-type.d.mts.map +1 -1
- package/dist/guard/is-type.mjs +201 -238
- package/dist/guard/is-type.mjs.map +1 -1
- package/dist/guard/key-is-in.d.mts +22 -139
- package/dist/guard/key-is-in.d.mts.map +1 -1
- package/dist/guard/key-is-in.mjs +22 -139
- package/dist/guard/key-is-in.mjs.map +1 -1
- package/dist/index.d.mts +0 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +0 -1
- package/dist/index.mjs.map +1 -1
- package/dist/iterator/range.d.mts +29 -62
- package/dist/iterator/range.d.mts.map +1 -1
- package/dist/iterator/range.mjs.map +1 -1
- package/dist/json/json.d.mts +191 -121
- package/dist/json/json.d.mts.map +1 -1
- package/dist/json/json.mjs +238 -136
- package/dist/json/json.mjs.map +1 -1
- package/dist/number/branded-types/finite-number.d.mts +24 -156
- package/dist/number/branded-types/finite-number.d.mts.map +1 -1
- package/dist/number/branded-types/finite-number.mjs +27 -159
- package/dist/number/branded-types/finite-number.mjs.map +1 -1
- package/dist/number/branded-types/int.d.mts +122 -120
- package/dist/number/branded-types/int.d.mts.map +1 -1
- package/dist/number/branded-types/int.mjs +122 -120
- package/dist/number/branded-types/int.mjs.map +1 -1
- package/dist/number/branded-types/int16.d.mts +22 -30
- package/dist/number/branded-types/int16.d.mts.map +1 -1
- package/dist/number/branded-types/int16.mjs +22 -30
- package/dist/number/branded-types/int16.mjs.map +1 -1
- package/dist/number/branded-types/int32.d.mts +22 -31
- package/dist/number/branded-types/int32.d.mts.map +1 -1
- package/dist/number/branded-types/int32.mjs +22 -31
- package/dist/number/branded-types/int32.mjs.map +1 -1
- package/dist/number/branded-types/non-negative-finite-number.d.mts +28 -36
- package/dist/number/branded-types/non-negative-finite-number.d.mts.map +1 -1
- package/dist/number/branded-types/non-negative-finite-number.mjs +31 -39
- package/dist/number/branded-types/non-negative-finite-number.mjs.map +1 -1
- package/dist/number/branded-types/non-negative-int16.d.mts +24 -34
- package/dist/number/branded-types/non-negative-int16.d.mts.map +1 -1
- package/dist/number/branded-types/non-negative-int16.mjs +24 -34
- package/dist/number/branded-types/non-negative-int16.mjs.map +1 -1
- package/dist/number/branded-types/non-negative-int32.d.mts +26 -35
- package/dist/number/branded-types/non-negative-int32.d.mts.map +1 -1
- package/dist/number/branded-types/non-negative-int32.mjs +26 -35
- package/dist/number/branded-types/non-negative-int32.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-finite-number.d.mts +22 -37
- package/dist/number/branded-types/non-zero-finite-number.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-finite-number.mjs +25 -40
- package/dist/number/branded-types/non-zero-finite-number.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-int.d.mts +15 -30
- package/dist/number/branded-types/non-zero-int.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-int.mjs +15 -30
- package/dist/number/branded-types/non-zero-int.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-int16.d.mts +27 -35
- package/dist/number/branded-types/non-zero-int16.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-int16.mjs +27 -35
- package/dist/number/branded-types/non-zero-int16.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-int32.d.mts +29 -36
- package/dist/number/branded-types/non-zero-int32.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-int32.mjs +29 -36
- package/dist/number/branded-types/non-zero-int32.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-safe-int.d.mts +37 -38
- package/dist/number/branded-types/non-zero-safe-int.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-safe-int.mjs +39 -40
- package/dist/number/branded-types/non-zero-safe-int.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-uint16.d.mts +24 -35
- package/dist/number/branded-types/non-zero-uint16.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-uint16.mjs +24 -35
- package/dist/number/branded-types/non-zero-uint16.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-uint32.d.mts +24 -35
- package/dist/number/branded-types/non-zero-uint32.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-uint32.mjs +24 -35
- package/dist/number/branded-types/non-zero-uint32.mjs.map +1 -1
- package/dist/number/branded-types/positive-finite-number.d.mts +26 -40
- package/dist/number/branded-types/positive-finite-number.d.mts.map +1 -1
- package/dist/number/branded-types/positive-finite-number.mjs +29 -43
- package/dist/number/branded-types/positive-finite-number.mjs.map +1 -1
- package/dist/number/branded-types/positive-int.d.mts +133 -123
- package/dist/number/branded-types/positive-int.d.mts.map +1 -1
- package/dist/number/branded-types/positive-int.mjs +133 -123
- package/dist/number/branded-types/positive-int.mjs.map +1 -1
- package/dist/number/branded-types/positive-int16.d.mts +24 -35
- package/dist/number/branded-types/positive-int16.d.mts.map +1 -1
- package/dist/number/branded-types/positive-int16.mjs +24 -35
- package/dist/number/branded-types/positive-int16.mjs.map +1 -1
- package/dist/number/branded-types/positive-int32.d.mts +24 -35
- package/dist/number/branded-types/positive-int32.d.mts.map +1 -1
- package/dist/number/branded-types/positive-int32.mjs +24 -35
- package/dist/number/branded-types/positive-int32.mjs.map +1 -1
- package/dist/number/branded-types/positive-safe-int.d.mts +159 -33
- package/dist/number/branded-types/positive-safe-int.d.mts.map +1 -1
- package/dist/number/branded-types/positive-safe-int.mjs +160 -34
- package/dist/number/branded-types/positive-safe-int.mjs.map +1 -1
- package/dist/number/branded-types/positive-uint16.d.mts +24 -35
- package/dist/number/branded-types/positive-uint16.d.mts.map +1 -1
- package/dist/number/branded-types/positive-uint16.mjs +24 -35
- package/dist/number/branded-types/positive-uint16.mjs.map +1 -1
- package/dist/number/branded-types/positive-uint32.d.mts +26 -36
- package/dist/number/branded-types/positive-uint32.d.mts.map +1 -1
- package/dist/number/branded-types/positive-uint32.mjs +26 -36
- package/dist/number/branded-types/positive-uint32.mjs.map +1 -1
- package/dist/number/branded-types/safe-int.d.mts +140 -99
- package/dist/number/branded-types/safe-int.d.mts.map +1 -1
- package/dist/number/branded-types/safe-int.mjs +142 -101
- package/dist/number/branded-types/safe-int.mjs.map +1 -1
- package/dist/number/branded-types/safe-uint.d.mts +24 -33
- package/dist/number/branded-types/safe-uint.d.mts.map +1 -1
- package/dist/number/branded-types/safe-uint.mjs +25 -34
- package/dist/number/branded-types/safe-uint.mjs.map +1 -1
- package/dist/number/branded-types/uint.d.mts +121 -30
- package/dist/number/branded-types/uint.d.mts.map +1 -1
- package/dist/number/branded-types/uint.mjs +121 -30
- package/dist/number/branded-types/uint.mjs.map +1 -1
- package/dist/number/branded-types/uint16.d.mts +26 -34
- package/dist/number/branded-types/uint16.d.mts.map +1 -1
- package/dist/number/branded-types/uint16.mjs +26 -34
- package/dist/number/branded-types/uint16.mjs.map +1 -1
- package/dist/number/branded-types/uint32.d.mts +26 -68
- package/dist/number/branded-types/uint32.d.mts.map +1 -1
- package/dist/number/branded-types/uint32.mjs +26 -68
- package/dist/number/branded-types/uint32.mjs.map +1 -1
- package/dist/number/enum/int8.d.mts +37 -101
- package/dist/number/enum/int8.d.mts.map +1 -1
- package/dist/number/enum/int8.mjs +39 -170
- package/dist/number/enum/int8.mjs.map +1 -1
- package/dist/number/enum/uint8.d.mts +45 -55
- package/dist/number/enum/uint8.d.mts.map +1 -1
- package/dist/number/enum/uint8.mjs +46 -155
- package/dist/number/enum/uint8.mjs.map +1 -1
- package/dist/number/num.d.mts +145 -206
- package/dist/number/num.d.mts.map +1 -1
- package/dist/number/num.mjs +143 -199
- package/dist/number/num.mjs.map +1 -1
- package/dist/number/refined-number-utils.d.mts +97 -21
- package/dist/number/refined-number-utils.d.mts.map +1 -1
- package/dist/number/refined-number-utils.mjs +91 -20
- package/dist/number/refined-number-utils.mjs.map +1 -1
- package/dist/object/object.d.mts +126 -208
- package/dist/object/object.d.mts.map +1 -1
- package/dist/object/object.mjs +68 -102
- package/dist/object/object.mjs.map +1 -1
- package/dist/others/cast-mutable.d.mts +12 -88
- package/dist/others/cast-mutable.d.mts.map +1 -1
- package/dist/others/cast-mutable.mjs +13 -89
- package/dist/others/cast-mutable.mjs.map +1 -1
- package/dist/others/cast-readonly.d.mts +12 -168
- package/dist/others/cast-readonly.d.mts.map +1 -1
- package/dist/others/cast-readonly.mjs +13 -169
- package/dist/others/cast-readonly.mjs.map +1 -1
- package/dist/others/if-then.d.mts +6 -83
- package/dist/others/if-then.d.mts.map +1 -1
- package/dist/others/if-then.mjs +6 -83
- package/dist/others/if-then.mjs.map +1 -1
- package/dist/others/map-nullable.d.mts +12 -136
- package/dist/others/map-nullable.d.mts.map +1 -1
- package/dist/others/map-nullable.mjs.map +1 -1
- package/dist/others/memoize-function.d.mts +14 -157
- package/dist/others/memoize-function.d.mts.map +1 -1
- package/dist/others/memoize-function.mjs +14 -157
- package/dist/others/memoize-function.mjs.map +1 -1
- package/dist/others/tuple.d.mts +33 -151
- package/dist/others/tuple.d.mts.map +1 -1
- package/dist/others/tuple.mjs +33 -151
- package/dist/others/tuple.mjs.map +1 -1
- package/dist/others/unknown-to-string.d.mts +11 -125
- package/dist/others/unknown-to-string.d.mts.map +1 -1
- package/dist/others/unknown-to-string.mjs +14 -127
- package/dist/others/unknown-to-string.mjs.map +1 -1
- package/dist/promise/promise.d.mts +33 -20
- package/dist/promise/promise.d.mts.map +1 -1
- package/dist/promise/promise.mjs +34 -21
- package/dist/promise/promise.mjs.map +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +54 -50
- package/src/array/impl/array-utils-creation.mts +192 -0
- package/src/array/{array-utils-creation.test.mts → impl/array-utils-creation.test.mts} +121 -72
- package/src/array/impl/array-utils-element-access.mts +115 -0
- package/src/array/impl/array-utils-element-access.test.mts +151 -0
- package/src/array/impl/array-utils-iterators.mts +79 -0
- package/src/array/impl/array-utils-iterators.test.mts +98 -0
- package/src/array/impl/array-utils-modification.mts +434 -0
- package/src/array/{array-utils-modification.test.mts → impl/array-utils-modification.test.mts} +41 -28
- package/src/array/{array-utils-overload-type-error.test.mts → impl/array-utils-overload-type-error.test.mts} +33 -33
- package/src/array/impl/array-utils-reducing-value.mts +551 -0
- package/src/array/{array-utils-reducing-value.test.mts → impl/array-utils-reducing-value.test.mts} +45 -50
- package/src/array/impl/array-utils-search.mts +509 -0
- package/src/array/impl/array-utils-search.test.mts +346 -0
- package/src/array/impl/array-utils-set-op.mts +166 -0
- package/src/array/{array-utils-set-op.test.mts → impl/array-utils-set-op.test.mts} +42 -35
- package/src/array/impl/array-utils-size.mts +30 -0
- package/src/array/impl/array-utils-size.test.mts +9 -0
- package/src/array/impl/array-utils-slice-clamped.mts +51 -0
- package/src/array/{array-utils-slice-clamped.test.mts → impl/array-utils-slice-clamped.test.mts} +12 -12
- package/src/array/impl/array-utils-slicing.mts +275 -0
- package/src/array/impl/array-utils-slicing.test.mts +158 -0
- package/src/array/impl/array-utils-transformation.mts +746 -0
- package/src/array/{array-utils-transformation.test.mts → impl/array-utils-transformation.test.mts} +662 -889
- package/src/array/impl/array-utils-validation.mts +241 -0
- package/src/array/{array-utils-validation.test.mts → impl/array-utils-validation.test.mts} +194 -107
- package/src/array/{array.test.mts → impl/array.test.mts} +2 -2
- package/src/array/impl/index.mts +12 -0
- package/src/array/index.mts +1 -1
- package/src/collections/imap-mapped.mts +99 -265
- package/src/collections/imap.mts +477 -174
- package/src/collections/imap.test.mts +12 -19
- package/src/collections/iset-mapped.mts +892 -358
- package/src/collections/iset.mts +429 -213
- package/src/collections/queue.mts +174 -200
- package/src/collections/stack.mts +172 -245
- package/src/collections/stack.test.mts +9 -1
- package/src/entry-point.mts +2 -0
- package/src/expect-type.mts +43 -172
- package/src/functional/match.mts +35 -145
- package/src/functional/optional.mts +285 -163
- package/src/functional/optional.test.mts +4 -1
- package/src/functional/pipe.mts +60 -113
- package/src/functional/result.mts +452 -351
- package/src/functional/result.test.mts +9 -2
- package/src/globals.d.mts +12 -5
- package/src/guard/has-key.mts +23 -74
- package/src/guard/is-non-empty-string.mts +20 -87
- package/src/guard/is-non-null-object.mts +14 -84
- package/src/guard/is-non-null-object.test.mts +1 -1
- package/src/guard/is-primitive.mts +13 -126
- package/src/guard/is-primitive.test.mts +1 -1
- package/src/guard/is-record.mts +21 -132
- package/src/guard/is-record.test.mts +0 -1
- package/src/guard/is-type.mts +201 -238
- package/src/guard/is-type.test.mts +7 -7
- package/src/guard/key-is-in.mts +22 -139
- package/src/index.mts +0 -1
- package/src/iterator/range.mts +29 -62
- package/src/json/json.mts +202 -134
- package/src/json/json.test.mts +1 -3
- package/src/number/branded-types/finite-number.mts +27 -159
- package/src/number/branded-types/int.mts +122 -120
- package/src/number/branded-types/int16.mts +22 -30
- package/src/number/branded-types/int16.test.mts +24 -24
- package/src/number/branded-types/int32.mts +22 -31
- package/src/number/branded-types/int32.test.mts +39 -39
- package/src/number/branded-types/non-negative-finite-number.mts +31 -39
- package/src/number/branded-types/non-negative-int16.mts +24 -34
- package/src/number/branded-types/non-negative-int16.test.mts +16 -16
- package/src/number/branded-types/non-negative-int32.mts +26 -35
- package/src/number/branded-types/non-negative-int32.test.mts +30 -30
- package/src/number/branded-types/non-zero-finite-number.mts +25 -40
- package/src/number/branded-types/non-zero-int.mts +15 -30
- package/src/number/branded-types/non-zero-int16.mts +27 -35
- package/src/number/branded-types/non-zero-int16.test.mts +26 -26
- package/src/number/branded-types/non-zero-int32.mts +29 -36
- package/src/number/branded-types/non-zero-int32.test.mts +45 -42
- package/src/number/branded-types/non-zero-safe-int.mts +39 -40
- package/src/number/branded-types/non-zero-uint16.mts +24 -35
- package/src/number/branded-types/non-zero-uint16.test.mts +16 -16
- package/src/number/branded-types/non-zero-uint32.mts +24 -35
- package/src/number/branded-types/non-zero-uint32.test.mts +28 -28
- package/src/number/branded-types/positive-finite-number.mts +29 -43
- package/src/number/branded-types/positive-int.mts +134 -124
- package/src/number/branded-types/positive-int16.mts +24 -35
- package/src/number/branded-types/positive-int16.test.mts +14 -14
- package/src/number/branded-types/positive-int32.mts +24 -35
- package/src/number/branded-types/positive-int32.test.mts +26 -26
- package/src/number/branded-types/positive-safe-int.mts +160 -34
- package/src/number/branded-types/positive-uint16.mts +24 -35
- package/src/number/branded-types/positive-uint16.test.mts +16 -16
- package/src/number/branded-types/positive-uint32.mts +26 -36
- package/src/number/branded-types/positive-uint32.test.mts +31 -28
- package/src/number/branded-types/safe-int.mts +142 -101
- package/src/number/branded-types/safe-uint.mts +25 -34
- package/src/number/branded-types/uint.mts +121 -30
- package/src/number/branded-types/uint16.mts +26 -34
- package/src/number/branded-types/uint16.test.mts +16 -16
- package/src/number/branded-types/uint32.mts +26 -68
- package/src/number/branded-types/uint32.test.mts +28 -28
- package/src/number/enum/int8.mts +39 -170
- package/src/number/enum/uint8.mts +46 -155
- package/src/number/num.mts +157 -212
- package/src/number/num.test.mts +4 -4
- package/src/number/refined-number-utils.mts +109 -26
- package/src/object/object.mts +130 -212
- package/src/object/object.test.mts +29 -0
- package/src/others/cast-mutable.mts +13 -89
- package/src/others/cast-mutable.test.mts +80 -0
- package/src/others/cast-readonly.mts +13 -169
- package/src/others/if-then.mts +6 -83
- package/src/others/map-nullable.mts +12 -136
- package/src/others/map-nullable.test.mts +6 -6
- package/src/others/memoize-function.mts +14 -157
- package/src/others/tuple.mts +33 -151
- package/src/others/unknown-to-string.mts +15 -127
- package/src/others/unknown-to-string.test.mts +14 -2
- package/src/promise/promise.mts +34 -21
- package/src/promise/promise.test.mts +43 -0
- package/dist/array/array-utils.d.mts +0 -2956
- package/dist/array/array-utils.d.mts.map +0 -1
- package/dist/array/array-utils.mjs +0 -1838
- package/dist/array/array-utils.mjs.map +0 -1
- package/src/array/array-utils-search.test.mts +0 -169
- package/src/array/array-utils-slicing.test.mts +0 -274
- package/src/array/array-utils.mts +0 -4834
package/src/array/{array-utils-transformation.test.mts → impl/array-utils-transformation.test.mts}
RENAMED
|
@@ -1,151 +1,185 @@
|
|
|
1
|
-
import { IMap } from '
|
|
2
|
-
import { expectType } from '
|
|
3
|
-
import { Optional } from '
|
|
4
|
-
import { SafeUint } from '
|
|
5
|
-
import {
|
|
1
|
+
import { IMap } from '../../collections/index.mjs';
|
|
2
|
+
import { expectType } from '../../expect-type.mjs';
|
|
3
|
+
import { Optional } from '../../functional/index.mjs';
|
|
4
|
+
import { SafeUint } from '../../number/index.mjs';
|
|
5
|
+
import {
|
|
6
|
+
concat,
|
|
7
|
+
filter,
|
|
8
|
+
filterNot,
|
|
9
|
+
flat,
|
|
10
|
+
flatMap,
|
|
11
|
+
groupBy,
|
|
12
|
+
map,
|
|
13
|
+
partition,
|
|
14
|
+
scan,
|
|
15
|
+
toReversed,
|
|
16
|
+
toSorted,
|
|
17
|
+
toSortedBy,
|
|
18
|
+
uniq,
|
|
19
|
+
uniqBy,
|
|
20
|
+
zip,
|
|
21
|
+
} from './array-utils-transformation.mjs';
|
|
6
22
|
|
|
7
23
|
describe('Arr transformations', () => {
|
|
8
|
-
describe('
|
|
9
|
-
const
|
|
24
|
+
describe('map', () => {
|
|
25
|
+
const mapped = map([1, 2, 3], (x, i): number => x * x * i);
|
|
10
26
|
|
|
11
|
-
|
|
12
|
-
const result = Arr.partition(xs, 4);
|
|
27
|
+
expectType<typeof mapped, ArrayOfLength<3, number>>('=');
|
|
13
28
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
| 1
|
|
18
|
-
| 2
|
|
19
|
-
| 3
|
|
20
|
-
| 4
|
|
21
|
-
| 5
|
|
22
|
-
| 6
|
|
23
|
-
| 7
|
|
24
|
-
| 8
|
|
25
|
-
| 9
|
|
26
|
-
| 10
|
|
27
|
-
| 11
|
|
28
|
-
| 12
|
|
29
|
-
)[])[]
|
|
30
|
-
>('=');
|
|
29
|
+
test('case 1', () => {
|
|
30
|
+
expect(mapped).toStrictEqual([0, 4, 18]);
|
|
31
|
+
});
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
39
|
-
}
|
|
33
|
+
test('should work with empty tuple', () => {
|
|
34
|
+
const empty = [] as const;
|
|
35
|
+
const mappedEmpty = map(empty, (x) => String(x));
|
|
36
|
+
expectType<typeof mappedEmpty, readonly []>('=');
|
|
37
|
+
expect(mappedEmpty).toStrictEqual([]);
|
|
38
|
+
});
|
|
40
39
|
|
|
41
|
-
{
|
|
42
|
-
const
|
|
40
|
+
test('should preserve tuple length with different types', () => {
|
|
41
|
+
const mixed = [1, 'hello', true] as const;
|
|
42
|
+
const mappedMixed = map(mixed, (x) => typeof x);
|
|
43
|
+
expectType<typeof mappedMixed, readonly [string, string, string]>('<=');
|
|
44
|
+
expect(mappedMixed).toStrictEqual(['number', 'string', 'boolean']);
|
|
45
|
+
});
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
| 7
|
|
54
|
-
| 8
|
|
55
|
-
| 9
|
|
56
|
-
| 10
|
|
57
|
-
| 11
|
|
58
|
-
| 12
|
|
59
|
-
)[])[]
|
|
60
|
-
>('=');
|
|
47
|
+
test('should work with index parameter', () => {
|
|
48
|
+
const tuple = ['a', 'b', 'c'] as const;
|
|
49
|
+
const mappedWithIndex = map(tuple, (x, i) => `${i}:${x}`);
|
|
50
|
+
expectType<typeof mappedWithIndex, readonly [string, string, string]>(
|
|
51
|
+
'<=',
|
|
52
|
+
);
|
|
53
|
+
expect(mappedWithIndex).toStrictEqual(['0:a', '1:b', '2:c']);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
61
56
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
[7, 8, 9],
|
|
67
|
-
[10, 11, 12],
|
|
68
|
-
]);
|
|
69
|
-
});
|
|
70
|
-
}
|
|
57
|
+
describe('scan', () => {
|
|
58
|
+
test('should compute running sum', () => {
|
|
59
|
+
const numbers = [1, 2, 3, 4];
|
|
60
|
+
const runningSum = scan(numbers, (acc, curr) => acc + curr, 0);
|
|
71
61
|
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
expectType<typeof runningSum, readonly [number, ...number[]]>('<=');
|
|
63
|
+
expect(runningSum).toStrictEqual([0, 1, 3, 6, 10]);
|
|
64
|
+
});
|
|
74
65
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
| 1
|
|
79
|
-
| 2
|
|
80
|
-
| 3
|
|
81
|
-
| 4
|
|
82
|
-
| 5
|
|
83
|
-
| 6
|
|
84
|
-
| 7
|
|
85
|
-
| 8
|
|
86
|
-
| 9
|
|
87
|
-
| 10
|
|
88
|
-
| 11
|
|
89
|
-
| 12
|
|
90
|
-
)[])[]
|
|
91
|
-
>('=');
|
|
66
|
+
test('should include initial value as first element', () => {
|
|
67
|
+
const numbers = [10, 20, 30];
|
|
68
|
+
const result = scan(numbers, (acc, curr) => acc + curr, 100);
|
|
92
69
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
[6, 7, 8, 9, 10],
|
|
97
|
-
[11, 12],
|
|
98
|
-
]);
|
|
99
|
-
});
|
|
100
|
-
}
|
|
70
|
+
expect(result).toStrictEqual([100, 110, 130, 160]);
|
|
71
|
+
expect(result).toHaveLength(4); // original length + 1
|
|
72
|
+
});
|
|
101
73
|
|
|
102
|
-
test('should
|
|
103
|
-
const
|
|
104
|
-
const result = Arr.partition(numbers, 2);
|
|
74
|
+
test('should work with curried version', () => {
|
|
75
|
+
const scanSum = scan<number, number>((acc, curr) => acc + curr, 0);
|
|
105
76
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
]);
|
|
77
|
+
const result1 = scanSum([1, 2, 3]);
|
|
78
|
+
const result2 = scanSum([5, 10]);
|
|
79
|
+
|
|
80
|
+
expect(result1).toStrictEqual([0, 1, 3, 6]);
|
|
81
|
+
expect(result2).toStrictEqual([0, 5, 15]);
|
|
111
82
|
});
|
|
112
83
|
|
|
113
|
-
test('should
|
|
114
|
-
const numbers = [
|
|
115
|
-
const
|
|
84
|
+
test('should provide index to reducer', () => {
|
|
85
|
+
const numbers = [10, 20, 30];
|
|
86
|
+
const mut_indices: number[] = [];
|
|
116
87
|
|
|
117
|
-
|
|
88
|
+
scan(
|
|
89
|
+
numbers,
|
|
90
|
+
(acc, curr, index) => {
|
|
91
|
+
mut_indices.push(index);
|
|
92
|
+
return acc + curr;
|
|
93
|
+
},
|
|
94
|
+
0,
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
expect(mut_indices).toStrictEqual([0, 1, 2]);
|
|
118
98
|
});
|
|
119
99
|
|
|
120
|
-
test('should work with
|
|
100
|
+
test('should work with empty array', () => {
|
|
101
|
+
const empty: readonly number[] = [];
|
|
102
|
+
const result = scan(empty, (acc, curr) => acc + curr, 42);
|
|
103
|
+
|
|
104
|
+
expect(result).toStrictEqual([42]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('should work with different accumulator and element types', () => {
|
|
108
|
+
const strings = ['a', 'b', 'c'];
|
|
109
|
+
const result = scan(strings, (acc, curr) => acc + curr.length, 0);
|
|
110
|
+
|
|
111
|
+
expectType<typeof result, readonly [number, ...number[]]>('<=');
|
|
112
|
+
expect(result).toStrictEqual([0, 1, 2, 3]);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test('should compute running product', () => {
|
|
116
|
+
const numbers = [2, 3, 4];
|
|
117
|
+
const runningProduct = scan(numbers, (acc, curr) => acc * curr, 1);
|
|
118
|
+
|
|
119
|
+
expect(runningProduct).toStrictEqual([1, 2, 6, 24]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('should work with objects', () => {
|
|
123
|
+
const items = [{ value: 10 }, { value: 20 }, { value: 30 }] as const;
|
|
124
|
+
|
|
125
|
+
const result = scan(items, (acc, curr) => acc + curr.value, 0);
|
|
126
|
+
|
|
127
|
+
expect(result).toStrictEqual([0, 10, 30, 60]);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('should preserve all intermediate values', () => {
|
|
121
131
|
const numbers = [1, 2, 3];
|
|
122
|
-
const result =
|
|
132
|
+
const result = scan(numbers, (acc, curr) => acc - curr, 10);
|
|
123
133
|
|
|
124
|
-
//
|
|
125
|
-
expect(result).toStrictEqual([]);
|
|
134
|
+
// 10 -> 10-1=9 -> 9-2=7 -> 7-3=4
|
|
135
|
+
expect(result).toStrictEqual([10, 9, 7, 4]);
|
|
126
136
|
});
|
|
137
|
+
});
|
|
127
138
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
139
|
+
describe('toReversed', () => {
|
|
140
|
+
{
|
|
141
|
+
const xs = [1, 2, 3] as const;
|
|
142
|
+
const _nativeResult = xs.toReversed();
|
|
131
143
|
|
|
132
|
-
|
|
144
|
+
expectType<typeof _nativeResult, (1 | 2 | 3)[]>('=');
|
|
145
|
+
|
|
146
|
+
const result = toReversed([1, 2, 3]);
|
|
147
|
+
|
|
148
|
+
expectType<typeof result, readonly [3, 2, 1]>('=');
|
|
149
|
+
|
|
150
|
+
test('case 1', () => {
|
|
151
|
+
expect(result).toStrictEqual([3, 2, 1]);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
test('should work with empty tuple', () => {
|
|
156
|
+
const empty = [] as const;
|
|
157
|
+
const reversed = toReversed(empty);
|
|
158
|
+
expectType<typeof reversed, readonly []>('=');
|
|
159
|
+
expect(reversed).toStrictEqual([]);
|
|
133
160
|
});
|
|
134
161
|
|
|
135
|
-
test('
|
|
136
|
-
const
|
|
137
|
-
const
|
|
162
|
+
test('should work with single element', () => {
|
|
163
|
+
const single = [42] as const;
|
|
164
|
+
const reversed = toReversed(single);
|
|
165
|
+
expectType<typeof reversed, readonly [42]>('=');
|
|
166
|
+
expect(reversed).toStrictEqual([42]);
|
|
167
|
+
});
|
|
138
168
|
|
|
139
|
-
|
|
169
|
+
test('should preserve mixed types in reverse order', () => {
|
|
170
|
+
const mixed = [1, 'hello', true, null] as const;
|
|
171
|
+
const reversed = toReversed(mixed);
|
|
172
|
+
expectType<typeof reversed, readonly [null, true, 'hello', 1]>('=');
|
|
173
|
+
expect(reversed).toStrictEqual([null, true, 'hello', 1]);
|
|
140
174
|
});
|
|
141
175
|
});
|
|
142
176
|
|
|
143
177
|
describe('toSorted', () => {
|
|
144
178
|
{
|
|
145
179
|
const xs = [2, 1, 3] as const;
|
|
146
|
-
const result =
|
|
180
|
+
const result = toSorted(xs);
|
|
147
181
|
|
|
148
|
-
expectType<typeof result,
|
|
182
|
+
expectType<typeof result, ArrayOfLength<3, 1 | 2 | 3>>('=');
|
|
149
183
|
|
|
150
184
|
test('case 1', () => {
|
|
151
185
|
expect(result).toStrictEqual([1, 2, 3]);
|
|
@@ -153,9 +187,9 @@ describe('Arr transformations', () => {
|
|
|
153
187
|
}
|
|
154
188
|
{
|
|
155
189
|
const xs = [2, 1, 3] as const;
|
|
156
|
-
const result =
|
|
190
|
+
const result = toSorted(xs, (a, b) => a - b);
|
|
157
191
|
|
|
158
|
-
expectType<typeof result,
|
|
192
|
+
expectType<typeof result, ArrayOfLength<3, 1 | 2 | 3>>('=');
|
|
159
193
|
|
|
160
194
|
test('case 2', () => {
|
|
161
195
|
expect(result).toStrictEqual([1, 2, 3]);
|
|
@@ -163,9 +197,9 @@ describe('Arr transformations', () => {
|
|
|
163
197
|
}
|
|
164
198
|
{
|
|
165
199
|
const xs = [2, 1, 3] as const;
|
|
166
|
-
const result =
|
|
200
|
+
const result = toSorted(xs, (a, b) => b - a);
|
|
167
201
|
|
|
168
|
-
expectType<typeof result,
|
|
202
|
+
expectType<typeof result, ArrayOfLength<3, 1 | 2 | 3>>('=');
|
|
169
203
|
|
|
170
204
|
test('case 3', () => {
|
|
171
205
|
expect(result).toStrictEqual([3, 2, 1]);
|
|
@@ -176,7 +210,7 @@ describe('Arr transformations', () => {
|
|
|
176
210
|
describe('toSortedBy', () => {
|
|
177
211
|
{
|
|
178
212
|
const xs = [{ v: 2 }, { v: 1 }, { v: 3 }] as const;
|
|
179
|
-
const sorted =
|
|
213
|
+
const sorted = toSortedBy(xs, (x) => x.v);
|
|
180
214
|
|
|
181
215
|
expectType<
|
|
182
216
|
typeof sorted,
|
|
@@ -189,7 +223,7 @@ describe('Arr transformations', () => {
|
|
|
189
223
|
}
|
|
190
224
|
{
|
|
191
225
|
const xs = [{ v: 2 }, { v: 1 }, { v: 3 }] as const;
|
|
192
|
-
const sorted =
|
|
226
|
+
const sorted = toSortedBy(
|
|
193
227
|
xs,
|
|
194
228
|
(x) => x.v,
|
|
195
229
|
(a, b) => a - b,
|
|
@@ -211,7 +245,7 @@ describe('Arr transformations', () => {
|
|
|
211
245
|
{ name: 'Bob', age: 20 },
|
|
212
246
|
{ name: 'Charlie', age: 25 },
|
|
213
247
|
];
|
|
214
|
-
const result =
|
|
248
|
+
const result = toSortedBy(people, (person) => person.age);
|
|
215
249
|
|
|
216
250
|
expect(result).toHaveLength(3);
|
|
217
251
|
expect(result[0]?.name).toBe('Bob');
|
|
@@ -221,7 +255,7 @@ describe('Arr transformations', () => {
|
|
|
221
255
|
|
|
222
256
|
test('should work with string sorting', () => {
|
|
223
257
|
const words = ['banana', 'apple', 'cherry'];
|
|
224
|
-
const result =
|
|
258
|
+
const result = toSortedBy(
|
|
225
259
|
words,
|
|
226
260
|
(word: string) => word,
|
|
227
261
|
(a: string, b: string) => a.localeCompare(b),
|
|
@@ -231,267 +265,81 @@ describe('Arr transformations', () => {
|
|
|
231
265
|
|
|
232
266
|
test('should work with custom key extraction', () => {
|
|
233
267
|
const items = ['hello', 'hi', 'welcome', 'bye'];
|
|
234
|
-
const result =
|
|
268
|
+
const result = toSortedBy(items, (item) => item.length);
|
|
235
269
|
expect(result).toStrictEqual(['hi', 'bye', 'hello', 'welcome']);
|
|
236
270
|
});
|
|
237
271
|
|
|
238
272
|
test('should work with empty array', () => {
|
|
239
273
|
const empty: readonly { value: number }[] = [];
|
|
240
|
-
const result =
|
|
274
|
+
const result = toSortedBy(empty, (item) => item.value);
|
|
241
275
|
expect(result).toStrictEqual([]);
|
|
242
276
|
});
|
|
243
277
|
|
|
244
278
|
test('toSortedBy should work with empty array', () => {
|
|
245
279
|
const empty: readonly { value: number }[] = [];
|
|
246
|
-
const result =
|
|
280
|
+
const result = toSortedBy(empty, (item) => item.value);
|
|
247
281
|
expect(result).toStrictEqual([]);
|
|
248
282
|
});
|
|
249
283
|
});
|
|
250
284
|
|
|
251
|
-
describe('
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
{ x: 2, y: 2 },
|
|
258
|
-
{ x: 1, y: 3 },
|
|
259
|
-
] as const;
|
|
285
|
+
describe('filter', () => {
|
|
286
|
+
test('should filter array with predicate', () => {
|
|
287
|
+
const numbers = [1, 2, 3, 4, 5];
|
|
288
|
+
const evens = filter(numbers, (n) => n % 2 === 0);
|
|
289
|
+
expect(evens).toStrictEqual([2, 4]);
|
|
290
|
+
});
|
|
260
291
|
|
|
261
|
-
|
|
292
|
+
test('should work with type guards', () => {
|
|
293
|
+
const mixed: (string | number | null)[] = [
|
|
294
|
+
'hello',
|
|
295
|
+
42,
|
|
296
|
+
null,
|
|
297
|
+
'world',
|
|
298
|
+
123,
|
|
299
|
+
];
|
|
300
|
+
const strings = filter(mixed, (x): x is string => typeof x === 'string');
|
|
301
|
+
expectType<typeof strings, readonly string[]>('=');
|
|
302
|
+
expect(strings).toStrictEqual(['hello', 'world']);
|
|
303
|
+
});
|
|
262
304
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
| Readonly<{ x: 1; y: 2 }>
|
|
270
|
-
| Readonly<{ x: 1; y: 3 }>
|
|
271
|
-
| Readonly<{ x: 2; y: 1 }>
|
|
272
|
-
| Readonly<{ x: 2; y: 2 }>
|
|
273
|
-
| Readonly<{ x: 3; y: 1 }>
|
|
274
|
-
)[]
|
|
275
|
-
>
|
|
276
|
-
>('=');
|
|
305
|
+
test('should work with curried version', () => {
|
|
306
|
+
const isPositive = (n: number): boolean => n > 0;
|
|
307
|
+
const filterPositive = filter(isPositive);
|
|
308
|
+
const result = filterPositive([-1, 2, -3, 4]);
|
|
309
|
+
expect(result).toStrictEqual([2, 4]);
|
|
310
|
+
});
|
|
277
311
|
|
|
278
|
-
test('
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
| Readonly<{ x: 1; y: 2 }>
|
|
285
|
-
| Readonly<{ x: 1; y: 3 }>
|
|
286
|
-
| Readonly<{ x: 2; y: 1 }>
|
|
287
|
-
| Readonly<{ x: 2; y: 2 }>
|
|
288
|
-
| Readonly<{ x: 3; y: 1 }>
|
|
289
|
-
)[]
|
|
290
|
-
>([
|
|
291
|
-
[
|
|
292
|
-
1,
|
|
293
|
-
[
|
|
294
|
-
{ x: 1, y: 1 },
|
|
295
|
-
{ x: 1, y: 2 },
|
|
296
|
-
{ x: 1, y: 3 },
|
|
297
|
-
],
|
|
298
|
-
],
|
|
299
|
-
[
|
|
300
|
-
2,
|
|
301
|
-
[
|
|
302
|
-
{ x: 2, y: 1 },
|
|
303
|
-
{ x: 2, y: 2 },
|
|
304
|
-
],
|
|
305
|
-
],
|
|
306
|
-
[3, [{ x: 3, y: 1 }]],
|
|
307
|
-
]),
|
|
308
|
-
);
|
|
312
|
+
test('should work with curried type guards', () => {
|
|
313
|
+
const isString = (x: unknown): x is string => typeof x === 'string';
|
|
314
|
+
const filterStrings = filter(isString);
|
|
315
|
+
const result = filterStrings(['a', 1, 'b', 2]);
|
|
316
|
+
expectType<typeof result, readonly string[]>('=');
|
|
317
|
+
expect(result).toStrictEqual(['a', 'b']);
|
|
309
318
|
});
|
|
310
319
|
|
|
311
|
-
test('should
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
];
|
|
317
|
-
const grouped = Arr.groupBy(array, (item) => item.type);
|
|
318
|
-
|
|
319
|
-
expect(grouped.size).toBe(2);
|
|
320
|
-
const fruits = grouped.get('fruit');
|
|
321
|
-
const vegetables = grouped.get('vegetable');
|
|
322
|
-
|
|
323
|
-
expect(Optional.isSome(fruits)).toBe(true);
|
|
324
|
-
expect(Optional.isSome(vegetables)).toBe(true);
|
|
325
|
-
|
|
326
|
-
if (Optional.isSome(fruits)) {
|
|
327
|
-
expect(fruits.value).toHaveLength(2);
|
|
328
|
-
expect(fruits.value[0]?.name).toBe('apple');
|
|
329
|
-
expect(fruits.value[1]?.name).toBe('banana');
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (Optional.isSome(vegetables)) {
|
|
333
|
-
expect(vegetables.value).toHaveLength(1);
|
|
334
|
-
expect(vegetables.value[0]?.name).toBe('carrot');
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
test('should work with numeric keys', () => {
|
|
339
|
-
const numbers = [1, 2, 3, 4, 5, 6];
|
|
340
|
-
const grouped = Arr.groupBy(numbers, (n) => n % 2);
|
|
341
|
-
|
|
342
|
-
expect(grouped.size).toBe(2);
|
|
343
|
-
const evens = grouped.get(0);
|
|
344
|
-
const odds = grouped.get(1);
|
|
345
|
-
|
|
346
|
-
if (Optional.isSome(evens)) {
|
|
347
|
-
expect(evens.value).toStrictEqual([2, 4, 6]);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
if (Optional.isSome(odds)) {
|
|
351
|
-
expect(odds.value).toStrictEqual([1, 3, 5]);
|
|
352
|
-
}
|
|
320
|
+
test('should preserve array type with generic predicate', () => {
|
|
321
|
+
const tuple = [1, 2, 3] as const;
|
|
322
|
+
const filtered = filter(tuple, (x) => x > 1);
|
|
323
|
+
expectType<typeof filtered, readonly (1 | 2 | 3)[]>('=');
|
|
324
|
+
expect(filtered).toStrictEqual([2, 3]);
|
|
353
325
|
});
|
|
354
326
|
|
|
355
327
|
test('should work with empty array', () => {
|
|
356
|
-
const empty:
|
|
357
|
-
const
|
|
358
|
-
expect(grouped.size).toBe(0);
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
test('should handle all elements in same group', () => {
|
|
362
|
-
const array = [1, 2, 3, 4];
|
|
363
|
-
const grouped = Arr.groupBy(array, () => 'all');
|
|
364
|
-
|
|
365
|
-
expect(grouped.size).toBe(1);
|
|
366
|
-
const all = grouped.get('all');
|
|
367
|
-
|
|
368
|
-
if (Optional.isSome(all)) {
|
|
369
|
-
expect(all.value).toStrictEqual([1, 2, 3, 4]);
|
|
370
|
-
}
|
|
371
|
-
});
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
describe('zip', () => {
|
|
375
|
-
{
|
|
376
|
-
const xs = [1, 2, 3] as const;
|
|
377
|
-
const ys = [4, 5, 6] as const;
|
|
378
|
-
const zipped = Arr.zip(xs, ys);
|
|
379
|
-
|
|
380
|
-
expectType<
|
|
381
|
-
typeof zipped,
|
|
382
|
-
readonly [readonly [1, 4], readonly [2, 5], readonly [3, 6]]
|
|
383
|
-
>('=');
|
|
384
|
-
|
|
385
|
-
test('case 1', () => {
|
|
386
|
-
expect(zipped).toStrictEqual([
|
|
387
|
-
[1, 4],
|
|
388
|
-
[2, 5],
|
|
389
|
-
[3, 6],
|
|
390
|
-
]);
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
{
|
|
394
|
-
const xs: readonly number[] = [1, 2, 3];
|
|
395
|
-
const ys: readonly number[] = [4];
|
|
396
|
-
const zipped = Arr.zip(xs, ys);
|
|
397
|
-
|
|
398
|
-
expectType<typeof zipped, readonly (readonly [number, number])[]>('=');
|
|
399
|
-
|
|
400
|
-
test('case 2', () => {
|
|
401
|
-
expect(zipped).toStrictEqual([[1, 4]]);
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
{
|
|
405
|
-
const xs = [1] as const;
|
|
406
|
-
const ys: readonly number[] = [4, 5, 6];
|
|
407
|
-
const zipped = Arr.zip(xs, ys);
|
|
408
|
-
|
|
409
|
-
expectType<typeof zipped, readonly [readonly [1, number]]>('=');
|
|
410
|
-
|
|
411
|
-
test('case 3', () => {
|
|
412
|
-
expect(zipped).toStrictEqual([[1, 4]]);
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// testArrayEquality({
|
|
417
|
-
// testName: 'zip',
|
|
418
|
-
// target: zip([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]),
|
|
419
|
-
// toBe: [
|
|
420
|
-
// [0, 5],
|
|
421
|
-
// [1, 6],
|
|
422
|
-
// [2, 7],
|
|
423
|
-
// [3, 8],
|
|
424
|
-
// [4, 9],
|
|
425
|
-
// ],
|
|
426
|
-
// });
|
|
427
|
-
|
|
428
|
-
// testArrayEquality({
|
|
429
|
-
// testName: 'zipArrays 2 arrays',
|
|
430
|
-
// target: zipArrays([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]),
|
|
431
|
-
// toBe: [
|
|
432
|
-
// [0, 5],
|
|
433
|
-
// [1, 6],
|
|
434
|
-
// [2, 7],
|
|
435
|
-
// [3, 8],
|
|
436
|
-
// [4, 9],
|
|
437
|
-
// ],
|
|
438
|
-
// });
|
|
439
|
-
|
|
440
|
-
// testArrayEquality({
|
|
441
|
-
// testName: 'zipArrays 3 arrays',
|
|
442
|
-
// target: zipArrays(
|
|
443
|
-
// [0, 1, 2, 3, 4],
|
|
444
|
-
// [5, 6, 7, 8, 9, 999, 999],
|
|
445
|
-
// [10, 11, 12, 13, 14, 999]
|
|
446
|
-
// ),
|
|
447
|
-
// toBe: [
|
|
448
|
-
// [0, 5, 10],
|
|
449
|
-
// [1, 6, 11],
|
|
450
|
-
// [2, 7, 12],
|
|
451
|
-
// [3, 8, 13],
|
|
452
|
-
// [4, 9, 14],
|
|
453
|
-
// ],
|
|
454
|
-
// });
|
|
455
|
-
|
|
456
|
-
test('should zip two arrays', () => {
|
|
457
|
-
const arr1 = [1, 2, 3];
|
|
458
|
-
const arr2 = ['a', 'b', 'c'];
|
|
459
|
-
const result = Arr.zip(arr1, arr2);
|
|
460
|
-
expect(result).toStrictEqual([
|
|
461
|
-
[1, 'a'],
|
|
462
|
-
[2, 'b'],
|
|
463
|
-
[3, 'c'],
|
|
464
|
-
]);
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
test('should handle arrays of different lengths', () => {
|
|
468
|
-
const arr1 = [1, 2, 3, 4];
|
|
469
|
-
const arr2 = ['a', 'b'];
|
|
470
|
-
const result = Arr.zip(arr1, arr2);
|
|
471
|
-
expect(result).toStrictEqual([
|
|
472
|
-
[1, 'a'],
|
|
473
|
-
[2, 'b'],
|
|
474
|
-
]);
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
test('should work with empty arrays', () => {
|
|
478
|
-
const arr1: readonly number[] = [];
|
|
479
|
-
const arr2: readonly string[] = [];
|
|
480
|
-
const result = Arr.zip(arr1, arr2);
|
|
328
|
+
const empty: number[] = [];
|
|
329
|
+
const result = filter(empty, (n) => n > 0);
|
|
481
330
|
expect(result).toStrictEqual([]);
|
|
482
331
|
});
|
|
483
332
|
|
|
484
|
-
test('should
|
|
485
|
-
const
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
expect(result).toStrictEqual([]);
|
|
333
|
+
test('should pass index to predicate', () => {
|
|
334
|
+
const numbers = [10, 20, 30, 40];
|
|
335
|
+
const evenIndexes = filter(numbers, (_, i) => i % 2 === 0);
|
|
336
|
+
expect(evenIndexes).toStrictEqual([10, 30]);
|
|
489
337
|
});
|
|
490
338
|
});
|
|
491
339
|
|
|
492
340
|
describe('filterNot', () => {
|
|
493
341
|
const xs = [1, 2, 3] as const;
|
|
494
|
-
const filtered =
|
|
342
|
+
const filtered = filterNot(xs, (x) => x % 2 === 0);
|
|
495
343
|
|
|
496
344
|
expectType<typeof filtered, readonly (1 | 2 | 3)[]>('=');
|
|
497
345
|
|
|
@@ -500,70 +348,28 @@ describe('Arr transformations', () => {
|
|
|
500
348
|
});
|
|
501
349
|
});
|
|
502
350
|
|
|
503
|
-
describe('concat', () => {
|
|
504
|
-
const xs = [1, 2, 3] as const;
|
|
505
|
-
const ys = [4, 5] as const;
|
|
506
|
-
const result = Arr.concat(xs, ys);
|
|
507
|
-
|
|
508
|
-
expectType<typeof result, readonly [1, 2, 3, 4, 5]>('=');
|
|
509
|
-
|
|
510
|
-
test('case 1', () => {
|
|
511
|
-
expect(result).toStrictEqual([1, 2, 3, 4, 5]);
|
|
512
|
-
});
|
|
513
|
-
|
|
514
|
-
// testArrayEquality({
|
|
515
|
-
// testName: 'concat 2 arrays',
|
|
516
|
-
// target: concat([1, 2, 3], [4, 5, 6]),
|
|
517
|
-
// toBe: [1, 2, 3, 4, 5, 6],
|
|
518
|
-
// });
|
|
519
|
-
|
|
520
|
-
// testArrayEquality({
|
|
521
|
-
// testName: 'concat 2 arrays',
|
|
522
|
-
// target: concat([1, 2, 3], []),
|
|
523
|
-
// toBe: [1, 2, 3],
|
|
524
|
-
// });
|
|
525
|
-
|
|
526
|
-
// testArrayEquality({
|
|
527
|
-
// testName: 'concat 2 arrays',
|
|
528
|
-
// target: concat([], [4, 5, 6]),
|
|
529
|
-
// toBe: [4, 5, 6],
|
|
530
|
-
// });
|
|
531
|
-
|
|
532
|
-
// testArrayEquality({
|
|
533
|
-
// testName: 'concat 2 arrays',
|
|
534
|
-
// target: concat([], []),
|
|
535
|
-
// toBe: [],
|
|
536
|
-
// });
|
|
537
|
-
|
|
538
|
-
// testArrayEquality({
|
|
539
|
-
// testName: 'concat 2 arrays',
|
|
540
|
-
// target: concat(['1', '2', '3'], [4, 5, 6]),
|
|
541
|
-
// toBe: ['1', '2', '3', 4, 5, 6],
|
|
542
|
-
// });
|
|
543
|
-
});
|
|
544
|
-
|
|
545
351
|
describe('uniq', () => {
|
|
546
352
|
test('should remove duplicate primitives', () => {
|
|
547
353
|
const array = [1, 2, 2, 3, 1, 4, 3];
|
|
548
|
-
const result =
|
|
354
|
+
const result = uniq(array);
|
|
549
355
|
expect(result).toStrictEqual([1, 2, 3, 4]);
|
|
550
356
|
});
|
|
551
357
|
|
|
552
358
|
test('should work with strings', () => {
|
|
553
359
|
const array = ['a', 'b', 'a', 'c', 'b'];
|
|
554
|
-
const result =
|
|
360
|
+
const result = uniq(array);
|
|
555
361
|
expect(result).toStrictEqual(['a', 'b', 'c']);
|
|
556
362
|
});
|
|
557
363
|
|
|
558
364
|
test('should work with empty array', () => {
|
|
559
365
|
const array: readonly number[] = [];
|
|
560
|
-
const result =
|
|
366
|
+
const result = uniq(array);
|
|
561
367
|
expect(result).toStrictEqual([]);
|
|
562
368
|
});
|
|
563
369
|
|
|
564
370
|
test('should preserve order of first occurrence', () => {
|
|
565
371
|
const array = [3, 1, 2, 1, 3, 2];
|
|
566
|
-
const result =
|
|
372
|
+
const result = uniq(array);
|
|
567
373
|
expect(result).toStrictEqual([3, 1, 2]);
|
|
568
374
|
});
|
|
569
375
|
});
|
|
@@ -576,7 +382,7 @@ describe('Arr transformations', () => {
|
|
|
576
382
|
{ id: 1, name: 'Alice Duplicate' },
|
|
577
383
|
{ id: 3, name: 'Charlie' },
|
|
578
384
|
];
|
|
579
|
-
const result =
|
|
385
|
+
const result = uniqBy(array, (item) => item.id);
|
|
580
386
|
|
|
581
387
|
expect(result).toHaveLength(3);
|
|
582
388
|
expect(result[0]).toStrictEqual({ id: 1, name: 'Alice' });
|
|
@@ -586,7 +392,7 @@ describe('Arr transformations', () => {
|
|
|
586
392
|
|
|
587
393
|
test('should work with string key function', () => {
|
|
588
394
|
const words = ['hello', 'world', 'hi', 'welcome'];
|
|
589
|
-
const result =
|
|
395
|
+
const result = uniqBy(words, (word) => word.length);
|
|
590
396
|
|
|
591
397
|
expect(result).toHaveLength(3);
|
|
592
398
|
expect(result).toContain('hello'); // length 5
|
|
@@ -596,494 +402,43 @@ describe('Arr transformations', () => {
|
|
|
596
402
|
|
|
597
403
|
test('should work with empty array', () => {
|
|
598
404
|
const empty: readonly { id: number }[] = [];
|
|
599
|
-
const result =
|
|
405
|
+
const result = uniqBy(empty, (item) => item.id);
|
|
600
406
|
expect(result).toStrictEqual([]);
|
|
601
407
|
});
|
|
602
408
|
});
|
|
603
409
|
|
|
604
|
-
describe('
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
410
|
+
describe('flat', () => {
|
|
411
|
+
test('should flatten nested arrays with default depth 1', () => {
|
|
412
|
+
const nested = [
|
|
413
|
+
[1, 2],
|
|
414
|
+
[3, 4],
|
|
415
|
+
[5, 6],
|
|
416
|
+
];
|
|
417
|
+
const flattened = flat(nested);
|
|
418
|
+
expect(flattened).toStrictEqual([1, 2, 3, 4, 5, 6]);
|
|
611
419
|
});
|
|
612
420
|
|
|
613
|
-
test('should
|
|
614
|
-
const
|
|
615
|
-
const
|
|
616
|
-
|
|
617
|
-
expect(
|
|
421
|
+
test('should flatten with specified depth', () => {
|
|
422
|
+
const deepNested = [1, [2, [3, 4]], 5];
|
|
423
|
+
const flat1 = flat(deepNested, 1);
|
|
424
|
+
const flat2 = flat(deepNested, 2);
|
|
425
|
+
expect(flat1).toStrictEqual([1, 2, [3, 4], 5]);
|
|
426
|
+
expect(flat2).toStrictEqual([1, 2, 3, 4, 5]);
|
|
618
427
|
});
|
|
619
428
|
|
|
620
|
-
test('should
|
|
621
|
-
const
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
|
|
429
|
+
test('should work with curried version', () => {
|
|
430
|
+
const flattenOnce = flat();
|
|
431
|
+
const result = flattenOnce([
|
|
432
|
+
[1, 2],
|
|
433
|
+
[3, 4],
|
|
434
|
+
]);
|
|
435
|
+
expect(result).toStrictEqual([1, 2, 3, 4]);
|
|
625
436
|
});
|
|
626
437
|
|
|
627
|
-
test('should work with
|
|
628
|
-
const
|
|
629
|
-
const
|
|
630
|
-
|
|
631
|
-
'<=',
|
|
632
|
-
);
|
|
633
|
-
expect(mappedWithIndex).toStrictEqual(['0:a', '1:b', '2:c']);
|
|
634
|
-
});
|
|
635
|
-
});
|
|
636
|
-
|
|
637
|
-
describe('toReversed', () => {
|
|
638
|
-
{
|
|
639
|
-
const xs = [1, 2, 3] as const;
|
|
640
|
-
const _nativeResult = xs.toReversed();
|
|
641
|
-
|
|
642
|
-
expectType<typeof _nativeResult, (1 | 2 | 3)[]>('=');
|
|
643
|
-
|
|
644
|
-
const result = Arr.toReversed([1, 2, 3]);
|
|
645
|
-
|
|
646
|
-
expectType<typeof result, readonly [3, 2, 1]>('=');
|
|
647
|
-
|
|
648
|
-
test('case 1', () => {
|
|
649
|
-
expect(result).toStrictEqual([3, 2, 1]);
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
test('should work with empty tuple', () => {
|
|
654
|
-
const empty = [] as const;
|
|
655
|
-
const reversed = Arr.toReversed(empty);
|
|
656
|
-
expectType<typeof reversed, readonly []>('=');
|
|
657
|
-
expect(reversed).toStrictEqual([]);
|
|
658
|
-
});
|
|
659
|
-
|
|
660
|
-
test('should work with single element', () => {
|
|
661
|
-
const single = [42] as const;
|
|
662
|
-
const reversed = Arr.toReversed(single);
|
|
663
|
-
expectType<typeof reversed, readonly [42]>('=');
|
|
664
|
-
expect(reversed).toStrictEqual([42]);
|
|
665
|
-
});
|
|
666
|
-
|
|
667
|
-
test('should preserve mixed types in reverse order', () => {
|
|
668
|
-
const mixed = [1, 'hello', true, null] as const;
|
|
669
|
-
const reversed = Arr.toReversed(mixed);
|
|
670
|
-
expectType<typeof reversed, readonly [null, true, 'hello', 1]>('=');
|
|
671
|
-
expect(reversed).toStrictEqual([null, true, 'hello', 1]);
|
|
672
|
-
});
|
|
673
|
-
});
|
|
674
|
-
|
|
675
|
-
describe('filter', () => {
|
|
676
|
-
test('should filter array with predicate', () => {
|
|
677
|
-
const numbers = [1, 2, 3, 4, 5];
|
|
678
|
-
const evens = Arr.filter(numbers, (n) => n % 2 === 0);
|
|
679
|
-
expect(evens).toStrictEqual([2, 4]);
|
|
680
|
-
});
|
|
681
|
-
|
|
682
|
-
test('should work with type guards', () => {
|
|
683
|
-
const mixed: (string | number | null)[] = [
|
|
684
|
-
'hello',
|
|
685
|
-
42,
|
|
686
|
-
null,
|
|
687
|
-
'world',
|
|
688
|
-
123,
|
|
689
|
-
];
|
|
690
|
-
const strings = Arr.filter(
|
|
691
|
-
mixed,
|
|
692
|
-
(x): x is string => typeof x === 'string',
|
|
693
|
-
);
|
|
694
|
-
expectType<typeof strings, readonly string[]>('=');
|
|
695
|
-
expect(strings).toStrictEqual(['hello', 'world']);
|
|
696
|
-
});
|
|
697
|
-
|
|
698
|
-
test('should work with curried version', () => {
|
|
699
|
-
const isPositive = (n: number): boolean => n > 0;
|
|
700
|
-
const filterPositive = Arr.filter(isPositive);
|
|
701
|
-
const result = filterPositive([-1, 2, -3, 4]);
|
|
702
|
-
expect(result).toStrictEqual([2, 4]);
|
|
703
|
-
});
|
|
704
|
-
|
|
705
|
-
test('should work with curried type guards', () => {
|
|
706
|
-
const isString = (x: unknown): x is string => typeof x === 'string';
|
|
707
|
-
const filterStrings = Arr.filter(isString);
|
|
708
|
-
const result = filterStrings(['a', 1, 'b', 2]);
|
|
709
|
-
expectType<typeof result, readonly string[]>('=');
|
|
710
|
-
expect(result).toStrictEqual(['a', 'b']);
|
|
711
|
-
});
|
|
712
|
-
|
|
713
|
-
test('should preserve array type with generic predicate', () => {
|
|
714
|
-
const tuple = [1, 2, 3] as const;
|
|
715
|
-
const filtered = Arr.filter(tuple, (x) => x > 1);
|
|
716
|
-
expectType<typeof filtered, readonly (1 | 2 | 3)[]>('=');
|
|
717
|
-
expect(filtered).toStrictEqual([2, 3]);
|
|
718
|
-
});
|
|
719
|
-
|
|
720
|
-
test('should work with empty array', () => {
|
|
721
|
-
const empty: number[] = [];
|
|
722
|
-
const result = Arr.filter(empty, (n) => n > 0);
|
|
723
|
-
expect(result).toStrictEqual([]);
|
|
724
|
-
});
|
|
725
|
-
|
|
726
|
-
test('should pass index to predicate', () => {
|
|
727
|
-
const numbers = [10, 20, 30, 40];
|
|
728
|
-
const evenIndexes = Arr.filter(numbers, (_, i) => i % 2 === 0);
|
|
729
|
-
expect(evenIndexes).toStrictEqual([10, 30]);
|
|
730
|
-
});
|
|
731
|
-
});
|
|
732
|
-
|
|
733
|
-
describe('every', () => {
|
|
734
|
-
test('should return true when all elements satisfy predicate', () => {
|
|
735
|
-
const evens = [2, 4, 6, 8];
|
|
736
|
-
const allEven = Arr.every(evens, (n) => n % 2 === 0);
|
|
737
|
-
expect(allEven).toBe(true);
|
|
738
|
-
});
|
|
739
|
-
|
|
740
|
-
test('should return false when not all elements satisfy predicate', () => {
|
|
741
|
-
const mixed = [2, 3, 4, 6];
|
|
742
|
-
const allEven = Arr.every(mixed, (n) => n % 2 === 0);
|
|
743
|
-
expect(allEven).toBe(false);
|
|
744
|
-
});
|
|
745
|
-
|
|
746
|
-
test('should work as type guard', () => {
|
|
747
|
-
const mixed: (string | number)[] = ['hello', 'world'];
|
|
748
|
-
if (Arr.every(mixed, (x): x is string => typeof x === 'string')) {
|
|
749
|
-
// TypeScript narrows mixed to readonly string[] here
|
|
750
|
-
expect(mixed.every((s) => typeof s === 'string')).toBe(true);
|
|
751
|
-
}
|
|
752
|
-
});
|
|
753
|
-
|
|
754
|
-
test('should work with curried version', () => {
|
|
755
|
-
const isPositive = (n: number): boolean => n > 0;
|
|
756
|
-
const allPositive = Arr.every(isPositive);
|
|
757
|
-
expect(allPositive([1, 2, 3])).toBe(true);
|
|
758
|
-
expect(allPositive([1, -2, 3])).toBe(false);
|
|
759
|
-
});
|
|
760
|
-
|
|
761
|
-
test('should work with curried type guards', () => {
|
|
762
|
-
const isString = (x: unknown): x is string => typeof x === 'string';
|
|
763
|
-
const allStrings = Arr.every(isString);
|
|
764
|
-
const data: unknown[] = ['a', 'b', 'c'];
|
|
765
|
-
if (allStrings(data)) {
|
|
766
|
-
// TypeScript narrows data to readonly string[] here
|
|
767
|
-
expect(data.join('')).toBe('abc');
|
|
768
|
-
}
|
|
769
|
-
});
|
|
770
|
-
|
|
771
|
-
test('should return true for empty array', () => {
|
|
772
|
-
const empty: number[] = [];
|
|
773
|
-
const result = Arr.every(empty, (n) => n > 0);
|
|
774
|
-
expect(result).toBe(true);
|
|
775
|
-
});
|
|
776
|
-
|
|
777
|
-
test('should pass index to predicate', () => {
|
|
778
|
-
const numbers = [0, 1, 2, 3];
|
|
779
|
-
const indexMatchesValue = Arr.every(numbers, (val, idx) => val === idx);
|
|
780
|
-
expect(indexMatchesValue).toBe(true);
|
|
781
|
-
});
|
|
782
|
-
});
|
|
783
|
-
|
|
784
|
-
describe('some', () => {
|
|
785
|
-
test('should return true when at least one element satisfies predicate', () => {
|
|
786
|
-
const numbers = [1, 3, 5, 8];
|
|
787
|
-
const hasEven = Arr.some(numbers, (n) => n % 2 === 0);
|
|
788
|
-
expect(hasEven).toBe(true);
|
|
789
|
-
});
|
|
790
|
-
|
|
791
|
-
test('should return false when no elements satisfy predicate', () => {
|
|
792
|
-
const odds = [1, 3, 5, 7];
|
|
793
|
-
const hasEven = Arr.some(odds, (n) => n % 2 === 0);
|
|
794
|
-
expect(hasEven).toBe(false);
|
|
795
|
-
});
|
|
796
|
-
|
|
797
|
-
test('should work with curried version', () => {
|
|
798
|
-
const isNegative = (n: number): boolean => n < 0;
|
|
799
|
-
const hasNegative = Arr.some(isNegative);
|
|
800
|
-
expect(hasNegative([1, 2, -3])).toBe(true);
|
|
801
|
-
expect(hasNegative([1, 2, 3])).toBe(false);
|
|
802
|
-
});
|
|
803
|
-
|
|
804
|
-
test('should return false for empty array', () => {
|
|
805
|
-
const empty: number[] = [];
|
|
806
|
-
const result = Arr.some(empty, (n) => n > 0);
|
|
807
|
-
expect(result).toBe(false);
|
|
808
|
-
});
|
|
809
|
-
|
|
810
|
-
test('should pass index to predicate', () => {
|
|
811
|
-
const numbers = [10, 10, 10, 30];
|
|
812
|
-
const hasValueMatchingIndex = Arr.some(
|
|
813
|
-
numbers,
|
|
814
|
-
(val, idx) => val === idx * 10,
|
|
815
|
-
);
|
|
816
|
-
expect(hasValueMatchingIndex).toBe(true);
|
|
817
|
-
});
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
describe('entries', () => {
|
|
821
|
-
test('should return array of index-value pairs', () => {
|
|
822
|
-
const fruits = ['apple', 'banana', 'cherry'];
|
|
823
|
-
const entries = Array.from(Arr.entries(fruits));
|
|
824
|
-
expect(entries).toStrictEqual([
|
|
825
|
-
[0, 'apple'],
|
|
826
|
-
[1, 'banana'],
|
|
827
|
-
[2, 'cherry'],
|
|
828
|
-
]);
|
|
829
|
-
});
|
|
830
|
-
|
|
831
|
-
test('should work with tuples', () => {
|
|
832
|
-
const tuple = [10, 20, 30] as const;
|
|
833
|
-
const entries = Array.from(Arr.entries(tuple));
|
|
834
|
-
expectType<typeof entries, (readonly [Uint32, 10 | 20 | 30])[]>('=');
|
|
835
|
-
expect(entries).toStrictEqual([
|
|
836
|
-
[0, 10],
|
|
837
|
-
[1, 20],
|
|
838
|
-
[2, 30],
|
|
839
|
-
]);
|
|
840
|
-
});
|
|
841
|
-
|
|
842
|
-
test('should work with empty array', () => {
|
|
843
|
-
const empty: string[] = [];
|
|
844
|
-
const entries = Array.from(Arr.entries(empty));
|
|
845
|
-
expect(entries).toStrictEqual([]);
|
|
846
|
-
});
|
|
847
|
-
|
|
848
|
-
test('should preserve mixed types', () => {
|
|
849
|
-
const mixed = [1, 'hello', true] as const;
|
|
850
|
-
const entries = Array.from(Arr.entries(mixed));
|
|
851
|
-
expectType<typeof entries, (readonly [Uint32, 1 | 'hello' | true])[]>(
|
|
852
|
-
'=',
|
|
853
|
-
);
|
|
854
|
-
expect(entries).toStrictEqual([
|
|
855
|
-
[0, 1],
|
|
856
|
-
[1, 'hello'],
|
|
857
|
-
[2, true],
|
|
858
|
-
]);
|
|
859
|
-
});
|
|
860
|
-
});
|
|
861
|
-
|
|
862
|
-
describe('values', () => {
|
|
863
|
-
test('should return copy of array values', () => {
|
|
864
|
-
const numbers = [1, 2, 3];
|
|
865
|
-
const values = Array.from(Arr.values(numbers));
|
|
866
|
-
expect(values).toStrictEqual([1, 2, 3]);
|
|
867
|
-
expect(values).not.toBe(numbers); // Should be a copy
|
|
868
|
-
});
|
|
869
|
-
|
|
870
|
-
test('should work with tuples', () => {
|
|
871
|
-
const tuple = ['a', 'b', 'c'] as const;
|
|
872
|
-
const values = Array.from(Arr.values(tuple));
|
|
873
|
-
expectType<typeof values, ('a' | 'b' | 'c')[]>('=');
|
|
874
|
-
expect(values).toStrictEqual(['a', 'b', 'c']);
|
|
875
|
-
});
|
|
876
|
-
|
|
877
|
-
test('should work with empty array', () => {
|
|
878
|
-
const empty: number[] = [];
|
|
879
|
-
const values = Array.from(Arr.values(empty));
|
|
880
|
-
expect(values).toStrictEqual([]);
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
test('should preserve mixed types', () => {
|
|
884
|
-
const mixed = [1, 'hello', null] as const;
|
|
885
|
-
const values = Array.from(Arr.values(mixed));
|
|
886
|
-
expectType<typeof values, (1 | 'hello' | null)[]>('=');
|
|
887
|
-
expect(values).toStrictEqual([1, 'hello', null]);
|
|
888
|
-
});
|
|
889
|
-
});
|
|
890
|
-
|
|
891
|
-
describe('indices', () => {
|
|
892
|
-
test('should return array of indices', () => {
|
|
893
|
-
const fruits = ['apple', 'banana', 'cherry'];
|
|
894
|
-
const indices = Array.from(Arr.indices(fruits));
|
|
895
|
-
expect(indices).toStrictEqual([0, 1, 2]);
|
|
896
|
-
});
|
|
897
|
-
|
|
898
|
-
test('should work with tuples', () => {
|
|
899
|
-
const tuple = ['a', 'b'] as const;
|
|
900
|
-
const indices = Array.from(Arr.indices(tuple));
|
|
901
|
-
expectType<typeof indices, Uint32[]>('=');
|
|
902
|
-
expect(indices).toStrictEqual([0, 1]);
|
|
903
|
-
});
|
|
904
|
-
|
|
905
|
-
test('should work with empty array', () => {
|
|
906
|
-
const empty: string[] = [];
|
|
907
|
-
const indices = Array.from(Arr.indices(empty));
|
|
908
|
-
expect(indices).toStrictEqual([]);
|
|
909
|
-
});
|
|
910
|
-
|
|
911
|
-
test('should work with larger arrays', () => {
|
|
912
|
-
const large = Array.from({ length: 5 }, () => 'x');
|
|
913
|
-
const indices = Array.from(Arr.indices(large));
|
|
914
|
-
expect(indices).toStrictEqual([0, 1, 2, 3, 4]);
|
|
915
|
-
});
|
|
916
|
-
});
|
|
917
|
-
|
|
918
|
-
describe('findLast', () => {
|
|
919
|
-
test('should find last element matching predicate', () => {
|
|
920
|
-
const numbers = [1, 2, 3, 4, 5];
|
|
921
|
-
const lastEven = Arr.findLast(numbers, (n) => n % 2 === 0);
|
|
922
|
-
expect(Optional.isSome(lastEven)).toBe(true);
|
|
923
|
-
expect(Optional.unwrap(lastEven)).toBe(4);
|
|
924
|
-
});
|
|
925
|
-
|
|
926
|
-
test('should return None when no element matches', () => {
|
|
927
|
-
const odds = [1, 3, 5];
|
|
928
|
-
const lastEven = Arr.findLast(odds, (n) => n % 2 === 0);
|
|
929
|
-
expect(Optional.isNone(lastEven)).toBe(true);
|
|
930
|
-
});
|
|
931
|
-
|
|
932
|
-
test('should work with curried version', () => {
|
|
933
|
-
const isPositive = (n: number): boolean => n > 0;
|
|
934
|
-
const findLastPositive = Arr.findLast(isPositive);
|
|
935
|
-
const result = findLastPositive([-1, 2, -3, 4]);
|
|
936
|
-
expect(Optional.isSome(result)).toBe(true);
|
|
937
|
-
expect(Optional.unwrap(result)).toBe(4);
|
|
938
|
-
});
|
|
939
|
-
|
|
940
|
-
test('should work with empty array', () => {
|
|
941
|
-
const empty: number[] = [];
|
|
942
|
-
const result = Arr.findLast(empty, (n) => n > 0);
|
|
943
|
-
expect(Optional.isNone(result)).toBe(true);
|
|
944
|
-
});
|
|
945
|
-
|
|
946
|
-
test('should pass index and array to predicate', () => {
|
|
947
|
-
const numbers = [10, 20, 30, 40];
|
|
948
|
-
const lastWithIndex2 = Arr.findLast(numbers, (_, idx, arr) => {
|
|
949
|
-
expect(arr).toBe(numbers);
|
|
950
|
-
return idx === 2;
|
|
951
|
-
});
|
|
952
|
-
expect(Optional.unwrap(lastWithIndex2)).toBe(30);
|
|
953
|
-
});
|
|
954
|
-
|
|
955
|
-
test('should find last occurrence', () => {
|
|
956
|
-
const numbers = [1, 2, 2, 3, 2, 4];
|
|
957
|
-
const lastTwo = Arr.findLast(numbers, (n) => n === 2);
|
|
958
|
-
expect(Optional.unwrap(lastTwo)).toBe(2);
|
|
959
|
-
|
|
960
|
-
// Verify it's actually the last occurrence by checking behavior
|
|
961
|
-
const index = numbers.lastIndexOf(2);
|
|
962
|
-
expect(index).toBe(4); // Last 2 is at index 4
|
|
963
|
-
});
|
|
964
|
-
});
|
|
965
|
-
|
|
966
|
-
describe('findLastIndex', () => {
|
|
967
|
-
test('should find last index matching predicate', () => {
|
|
968
|
-
const numbers = [1, 2, 3, 4, 2, 5];
|
|
969
|
-
const lastTwoIndex = Arr.findLastIndex(numbers, (n) => n === 2);
|
|
970
|
-
expect(lastTwoIndex).toBe(4);
|
|
971
|
-
});
|
|
972
|
-
|
|
973
|
-
test('should return -1 when no element matches', () => {
|
|
974
|
-
const odds = [1, 3, 5];
|
|
975
|
-
const lastEvenIndex = Arr.findLastIndex(odds, (n) => n % 2 === 0);
|
|
976
|
-
expect(lastEvenIndex).toBe(-1);
|
|
977
|
-
});
|
|
978
|
-
|
|
979
|
-
test('should work with curried version', () => {
|
|
980
|
-
const isPositive = (n: number): boolean => n > 0;
|
|
981
|
-
const findLastPositiveIndex = Arr.findLastIndex(isPositive);
|
|
982
|
-
const result = findLastPositiveIndex([-1, 2, -3, 4, -5]);
|
|
983
|
-
expect(result).toBe(3); // index of last positive number (4)
|
|
984
|
-
});
|
|
985
|
-
|
|
986
|
-
test('should work with empty array', () => {
|
|
987
|
-
const empty: number[] = [];
|
|
988
|
-
const result = Arr.findLastIndex(empty, (n) => n > 0);
|
|
989
|
-
expect(result).toBe(-1);
|
|
990
|
-
});
|
|
991
|
-
|
|
992
|
-
test('should pass index and array to predicate', () => {
|
|
993
|
-
const numbers = [10, 20, 30, 40];
|
|
994
|
-
const lastWithIndex2OrHigher = Arr.findLastIndex(
|
|
995
|
-
numbers,
|
|
996
|
-
(_, idx, arr) => {
|
|
997
|
-
expect(arr).toBe(numbers);
|
|
998
|
-
return idx >= 2;
|
|
999
|
-
},
|
|
1000
|
-
);
|
|
1001
|
-
expect(lastWithIndex2OrHigher).toBe(3); // last index >= 2
|
|
1002
|
-
});
|
|
1003
|
-
|
|
1004
|
-
test('should find last occurrence with complex conditions', () => {
|
|
1005
|
-
const data = [
|
|
1006
|
-
{ id: 1, active: true },
|
|
1007
|
-
{ id: 2, active: false },
|
|
1008
|
-
{ id: 3, active: true },
|
|
1009
|
-
{ id: 4, active: false },
|
|
1010
|
-
{ id: 5, active: true },
|
|
1011
|
-
];
|
|
1012
|
-
const lastActiveIndex = Arr.findLastIndex(data, (item) => item.active);
|
|
1013
|
-
expect(lastActiveIndex).toBe(4); // last active item
|
|
1014
|
-
});
|
|
1015
|
-
|
|
1016
|
-
test('should work with tuples', () => {
|
|
1017
|
-
const tuple = [10, 20, 30, 20, 40] as const;
|
|
1018
|
-
const lastTwentyIndex = Arr.findLastIndex(tuple, (x) => x === 20);
|
|
1019
|
-
expect(lastTwentyIndex).toBe(3); // last occurrence of 20
|
|
1020
|
-
});
|
|
1021
|
-
|
|
1022
|
-
test('should search from end to beginning', () => {
|
|
1023
|
-
// Verify search order by using side effects
|
|
1024
|
-
const numbers = [1, 2, 3, 4, 5];
|
|
1025
|
-
const mut_searchOrder: number[] = [];
|
|
1026
|
-
|
|
1027
|
-
Arr.findLastIndex(numbers, (val, idx) => {
|
|
1028
|
-
mut_searchOrder.push(idx);
|
|
1029
|
-
return val === 3;
|
|
1030
|
-
});
|
|
1031
|
-
|
|
1032
|
-
// Should search from end: 4, 3, 2 (stops at 2 when found)
|
|
1033
|
-
expect(mut_searchOrder).toStrictEqual([4, 3, 2]);
|
|
1034
|
-
});
|
|
1035
|
-
|
|
1036
|
-
test('should handle single element array', () => {
|
|
1037
|
-
const single = [42];
|
|
1038
|
-
const foundIndex = Arr.findLastIndex(single, (n) => n === 42);
|
|
1039
|
-
const notFoundIndex = Arr.findLastIndex(single, (n) => n === 0);
|
|
1040
|
-
|
|
1041
|
-
expect(foundIndex).toBe(0);
|
|
1042
|
-
expect(notFoundIndex).toBe(-1);
|
|
1043
|
-
});
|
|
1044
|
-
|
|
1045
|
-
test('should work with string arrays', () => {
|
|
1046
|
-
const words = ['hello', 'world', 'test', 'hello', 'end'];
|
|
1047
|
-
const lastHelloIndex = Arr.findLastIndex(
|
|
1048
|
-
words,
|
|
1049
|
-
(word) => word === 'hello',
|
|
1050
|
-
);
|
|
1051
|
-
expect(lastHelloIndex).toBe(3);
|
|
1052
|
-
});
|
|
1053
|
-
});
|
|
1054
|
-
|
|
1055
|
-
describe('flat', () => {
|
|
1056
|
-
test('should flatten nested arrays with default depth 1', () => {
|
|
1057
|
-
const nested = [
|
|
1058
|
-
[1, 2],
|
|
1059
|
-
[3, 4],
|
|
1060
|
-
[5, 6],
|
|
1061
|
-
];
|
|
1062
|
-
const flattened = Arr.flat(nested);
|
|
1063
|
-
expect(flattened).toStrictEqual([1, 2, 3, 4, 5, 6]);
|
|
1064
|
-
});
|
|
1065
|
-
|
|
1066
|
-
test('should flatten with specified depth', () => {
|
|
1067
|
-
const deepNested = [1, [2, [3, 4]], 5];
|
|
1068
|
-
const flat1 = Arr.flat(deepNested, 1);
|
|
1069
|
-
const flat2 = Arr.flat(deepNested, 2);
|
|
1070
|
-
expect(flat1).toStrictEqual([1, 2, [3, 4], 5]);
|
|
1071
|
-
expect(flat2).toStrictEqual([1, 2, 3, 4, 5]);
|
|
1072
|
-
});
|
|
1073
|
-
|
|
1074
|
-
test('should work with curried version', () => {
|
|
1075
|
-
const flattenOnce = Arr.flat(1);
|
|
1076
|
-
const result = flattenOnce([
|
|
1077
|
-
[1, 2],
|
|
1078
|
-
[3, 4],
|
|
1079
|
-
]);
|
|
1080
|
-
expect(result).toStrictEqual([1, 2, 3, 4]);
|
|
1081
|
-
});
|
|
1082
|
-
|
|
1083
|
-
test('should work with empty arrays', () => {
|
|
1084
|
-
const withEmpties = [[1], [], [2, 3]];
|
|
1085
|
-
const flattened = Arr.flat(withEmpties);
|
|
1086
|
-
expect(flattened).toStrictEqual([1, 2, 3]);
|
|
438
|
+
test('should work with empty arrays', () => {
|
|
439
|
+
const withEmpties = [[1], [], [2, 3]];
|
|
440
|
+
const flattened = flat(withEmpties);
|
|
441
|
+
expect(flattened).toStrictEqual([1, 2, 3]);
|
|
1087
442
|
});
|
|
1088
443
|
|
|
1089
444
|
test('should work with depth 0', () => {
|
|
@@ -1091,7 +446,7 @@ describe('Arr transformations', () => {
|
|
|
1091
446
|
[1, 2],
|
|
1092
447
|
[3, 4],
|
|
1093
448
|
];
|
|
1094
|
-
const unflattened =
|
|
449
|
+
const unflattened = flat(nested, 0);
|
|
1095
450
|
expect(unflattened).toStrictEqual([
|
|
1096
451
|
[1, 2],
|
|
1097
452
|
[3, 4],
|
|
@@ -1100,7 +455,7 @@ describe('Arr transformations', () => {
|
|
|
1100
455
|
|
|
1101
456
|
test('should work with infinite depth', () => {
|
|
1102
457
|
const veryDeep = [1, [2, [3, [4, [5]]]]];
|
|
1103
|
-
const allFlat =
|
|
458
|
+
const allFlat = flat(veryDeep, SafeUint.MAX_VALUE);
|
|
1104
459
|
expect(allFlat).toStrictEqual([1, 2, 3, 4, 5]);
|
|
1105
460
|
});
|
|
1106
461
|
});
|
|
@@ -1108,7 +463,7 @@ describe('Arr transformations', () => {
|
|
|
1108
463
|
describe('flatMap', () => {
|
|
1109
464
|
test('should map and flatten results', () => {
|
|
1110
465
|
const words = ['hello', 'world'];
|
|
1111
|
-
const chars =
|
|
466
|
+
const chars = flatMap(words, (word) => word.split(''));
|
|
1112
467
|
expect(chars).toStrictEqual([
|
|
1113
468
|
'h',
|
|
1114
469
|
'e',
|
|
@@ -1124,39 +479,457 @@ describe('Arr transformations', () => {
|
|
|
1124
479
|
});
|
|
1125
480
|
|
|
1126
481
|
test('should work with curried version', () => {
|
|
1127
|
-
const splitWords =
|
|
482
|
+
const splitWords = flatMap((word: string) => word.split(''));
|
|
1128
483
|
const result = splitWords(['foo', 'bar']);
|
|
1129
484
|
expect(result).toStrictEqual(['f', 'o', 'o', 'b', 'a', 'r']);
|
|
1130
485
|
});
|
|
1131
486
|
|
|
1132
487
|
test('should work with numbers', () => {
|
|
1133
488
|
const numbers = [1, 2, 3];
|
|
1134
|
-
const doubled =
|
|
489
|
+
const doubled = flatMap(numbers, (n) => [n, n * 2]);
|
|
1135
490
|
expect(doubled).toStrictEqual([1, 2, 2, 4, 3, 6]);
|
|
1136
491
|
});
|
|
1137
492
|
|
|
1138
493
|
test('should pass index to mapping function', () => {
|
|
1139
494
|
const numbers = [10, 20];
|
|
1140
|
-
const result =
|
|
495
|
+
const result = flatMap(numbers, (n, i) => [n, i]);
|
|
1141
496
|
expect(result).toStrictEqual([10, 0, 20, 1]);
|
|
1142
497
|
});
|
|
1143
498
|
|
|
1144
499
|
test('should work with empty arrays', () => {
|
|
1145
500
|
const empty: string[] = [];
|
|
1146
|
-
const result =
|
|
501
|
+
const result = flatMap(empty, (s) => s.split(''));
|
|
1147
502
|
expect(result).toStrictEqual([]);
|
|
1148
503
|
});
|
|
1149
504
|
|
|
1150
505
|
test('should handle mapping to empty arrays', () => {
|
|
1151
506
|
const numbers = [1, 2, 3];
|
|
1152
|
-
const result =
|
|
507
|
+
const result = flatMap(numbers, (n) => (n % 2 === 0 ? [n] : []));
|
|
1153
508
|
expect(result).toStrictEqual([2]);
|
|
1154
509
|
});
|
|
1155
510
|
|
|
1156
511
|
test('should work with tuples', () => {
|
|
1157
512
|
const tuple = [1, 2] as const;
|
|
1158
|
-
const result =
|
|
513
|
+
const result = flatMap(tuple, (n) => [n, n]);
|
|
1159
514
|
expect(result).toStrictEqual([1, 1, 2, 2]);
|
|
1160
515
|
});
|
|
1161
516
|
});
|
|
517
|
+
|
|
518
|
+
describe('partition', () => {
|
|
519
|
+
const xs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] as const;
|
|
520
|
+
|
|
521
|
+
{
|
|
522
|
+
const result = partition(xs, 4);
|
|
523
|
+
|
|
524
|
+
expectType<
|
|
525
|
+
typeof result,
|
|
526
|
+
readonly (readonly (
|
|
527
|
+
| 1
|
|
528
|
+
| 2
|
|
529
|
+
| 3
|
|
530
|
+
| 4
|
|
531
|
+
| 5
|
|
532
|
+
| 6
|
|
533
|
+
| 7
|
|
534
|
+
| 8
|
|
535
|
+
| 9
|
|
536
|
+
| 10
|
|
537
|
+
| 11
|
|
538
|
+
| 12
|
|
539
|
+
)[])[]
|
|
540
|
+
>('=');
|
|
541
|
+
|
|
542
|
+
test('case 1', () => {
|
|
543
|
+
expect(result).toStrictEqual([
|
|
544
|
+
[1, 2, 3, 4],
|
|
545
|
+
[5, 6, 7, 8],
|
|
546
|
+
[9, 10, 11, 12],
|
|
547
|
+
]);
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
{
|
|
552
|
+
const result = partition(xs, 3);
|
|
553
|
+
|
|
554
|
+
expectType<
|
|
555
|
+
typeof result,
|
|
556
|
+
readonly (readonly (
|
|
557
|
+
| 1
|
|
558
|
+
| 2
|
|
559
|
+
| 3
|
|
560
|
+
| 4
|
|
561
|
+
| 5
|
|
562
|
+
| 6
|
|
563
|
+
| 7
|
|
564
|
+
| 8
|
|
565
|
+
| 9
|
|
566
|
+
| 10
|
|
567
|
+
| 11
|
|
568
|
+
| 12
|
|
569
|
+
)[])[]
|
|
570
|
+
>('=');
|
|
571
|
+
|
|
572
|
+
test('case 2', () => {
|
|
573
|
+
expect(result).toStrictEqual([
|
|
574
|
+
[1, 2, 3],
|
|
575
|
+
[4, 5, 6],
|
|
576
|
+
[7, 8, 9],
|
|
577
|
+
[10, 11, 12],
|
|
578
|
+
]);
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
{
|
|
583
|
+
const result = partition(xs, 5);
|
|
584
|
+
|
|
585
|
+
expectType<
|
|
586
|
+
typeof result,
|
|
587
|
+
readonly (readonly (
|
|
588
|
+
| 1
|
|
589
|
+
| 2
|
|
590
|
+
| 3
|
|
591
|
+
| 4
|
|
592
|
+
| 5
|
|
593
|
+
| 6
|
|
594
|
+
| 7
|
|
595
|
+
| 8
|
|
596
|
+
| 9
|
|
597
|
+
| 10
|
|
598
|
+
| 11
|
|
599
|
+
| 12
|
|
600
|
+
)[])[]
|
|
601
|
+
>('=');
|
|
602
|
+
|
|
603
|
+
test('case 3', () => {
|
|
604
|
+
expect(result).toStrictEqual([
|
|
605
|
+
[1, 2, 3, 4, 5],
|
|
606
|
+
[6, 7, 8, 9, 10],
|
|
607
|
+
[11, 12],
|
|
608
|
+
]);
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
test('should partition array into chunks', () => {
|
|
613
|
+
const numbers = [1, 2, 3, 4, 5, 6];
|
|
614
|
+
const result = partition(numbers, 2);
|
|
615
|
+
|
|
616
|
+
expect(result).toStrictEqual([
|
|
617
|
+
[1, 2],
|
|
618
|
+
[3, 4],
|
|
619
|
+
[5, 6],
|
|
620
|
+
]);
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
test('should handle arrays not evenly divisible by chunk size', () => {
|
|
624
|
+
const numbers = [1, 2, 3, 4, 5];
|
|
625
|
+
const result = partition(numbers, 2);
|
|
626
|
+
|
|
627
|
+
expect(result).toStrictEqual([[1, 2], [3, 4], [5]]);
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
test('should work with chunk size < 2 (returns empty)', () => {
|
|
631
|
+
const numbers = [1, 2, 3];
|
|
632
|
+
const result = partition(numbers, 1);
|
|
633
|
+
|
|
634
|
+
// According to docs, returns empty array if chunkSize < 2
|
|
635
|
+
expect(result).toStrictEqual([]);
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
test('should work with chunk size larger than array', () => {
|
|
639
|
+
const numbers = [1, 2];
|
|
640
|
+
const result = partition(numbers, 5);
|
|
641
|
+
|
|
642
|
+
expect(result).toStrictEqual([[1, 2]]);
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
test('partition should work with empty array', () => {
|
|
646
|
+
const empty: readonly number[] = [];
|
|
647
|
+
const result = partition(empty, 2);
|
|
648
|
+
|
|
649
|
+
expect(result).toStrictEqual([]);
|
|
650
|
+
});
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
describe('concat', () => {
|
|
654
|
+
const xs = [1, 2, 3] as const;
|
|
655
|
+
const ys = [4, 5] as const;
|
|
656
|
+
const result = concat(xs, ys);
|
|
657
|
+
|
|
658
|
+
expectType<typeof result, readonly [1, 2, 3, 4, 5]>('=');
|
|
659
|
+
|
|
660
|
+
test('case 1', () => {
|
|
661
|
+
expect(result).toStrictEqual([1, 2, 3, 4, 5]);
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
// testArrayEquality({
|
|
665
|
+
// testName: 'concat 2 arrays',
|
|
666
|
+
// target: concat([1, 2, 3], [4, 5, 6]),
|
|
667
|
+
// toBe: [1, 2, 3, 4, 5, 6],
|
|
668
|
+
// });
|
|
669
|
+
|
|
670
|
+
// testArrayEquality({
|
|
671
|
+
// testName: 'concat 2 arrays',
|
|
672
|
+
// target: concat([1, 2, 3], []),
|
|
673
|
+
// toBe: [1, 2, 3],
|
|
674
|
+
// });
|
|
675
|
+
|
|
676
|
+
// testArrayEquality({
|
|
677
|
+
// testName: 'concat 2 arrays',
|
|
678
|
+
// target: concat([], [4, 5, 6]),
|
|
679
|
+
// toBe: [4, 5, 6],
|
|
680
|
+
// });
|
|
681
|
+
|
|
682
|
+
// testArrayEquality({
|
|
683
|
+
// testName: 'concat 2 arrays',
|
|
684
|
+
// target: concat([], []),
|
|
685
|
+
// toBe: [],
|
|
686
|
+
// });
|
|
687
|
+
|
|
688
|
+
// testArrayEquality({
|
|
689
|
+
// testName: 'concat 2 arrays',
|
|
690
|
+
// target: concat(['1', '2', '3'], [4, 5, 6]),
|
|
691
|
+
// toBe: ['1', '2', '3', 4, 5, 6],
|
|
692
|
+
// });
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
describe('groupBy', () => {
|
|
696
|
+
const xs = [
|
|
697
|
+
{ x: 1, y: 1 },
|
|
698
|
+
{ x: 2, y: 1 },
|
|
699
|
+
{ x: 3, y: 1 },
|
|
700
|
+
{ x: 1, y: 2 },
|
|
701
|
+
{ x: 2, y: 2 },
|
|
702
|
+
{ x: 1, y: 3 },
|
|
703
|
+
] as const;
|
|
704
|
+
|
|
705
|
+
const result = groupBy(xs, (a) => a.x);
|
|
706
|
+
|
|
707
|
+
expectType<
|
|
708
|
+
typeof result,
|
|
709
|
+
IMap<
|
|
710
|
+
1 | 2 | 3,
|
|
711
|
+
readonly (
|
|
712
|
+
| Readonly<{ x: 1; y: 1 }>
|
|
713
|
+
| Readonly<{ x: 1; y: 2 }>
|
|
714
|
+
| Readonly<{ x: 1; y: 3 }>
|
|
715
|
+
| Readonly<{ x: 2; y: 1 }>
|
|
716
|
+
| Readonly<{ x: 2; y: 2 }>
|
|
717
|
+
| Readonly<{ x: 3; y: 1 }>
|
|
718
|
+
)[]
|
|
719
|
+
>
|
|
720
|
+
>('=');
|
|
721
|
+
|
|
722
|
+
test('case 1', () => {
|
|
723
|
+
expect(result).toStrictEqual(
|
|
724
|
+
IMap.create<
|
|
725
|
+
1 | 2 | 3,
|
|
726
|
+
readonly (
|
|
727
|
+
| Readonly<{ x: 1; y: 1 }>
|
|
728
|
+
| Readonly<{ x: 1; y: 2 }>
|
|
729
|
+
| Readonly<{ x: 1; y: 3 }>
|
|
730
|
+
| Readonly<{ x: 2; y: 1 }>
|
|
731
|
+
| Readonly<{ x: 2; y: 2 }>
|
|
732
|
+
| Readonly<{ x: 3; y: 1 }>
|
|
733
|
+
)[]
|
|
734
|
+
>([
|
|
735
|
+
[
|
|
736
|
+
1,
|
|
737
|
+
[
|
|
738
|
+
{ x: 1, y: 1 },
|
|
739
|
+
{ x: 1, y: 2 },
|
|
740
|
+
{ x: 1, y: 3 },
|
|
741
|
+
],
|
|
742
|
+
],
|
|
743
|
+
[
|
|
744
|
+
2,
|
|
745
|
+
[
|
|
746
|
+
{ x: 2, y: 1 },
|
|
747
|
+
{ x: 2, y: 2 },
|
|
748
|
+
],
|
|
749
|
+
],
|
|
750
|
+
[3, [{ x: 3, y: 1 }]],
|
|
751
|
+
]),
|
|
752
|
+
);
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
test('should group elements by key', () => {
|
|
756
|
+
const array = [
|
|
757
|
+
{ type: 'fruit', name: 'apple' },
|
|
758
|
+
{ type: 'vegetable', name: 'carrot' },
|
|
759
|
+
{ type: 'fruit', name: 'banana' },
|
|
760
|
+
];
|
|
761
|
+
const grouped = groupBy(array, (item) => item.type);
|
|
762
|
+
|
|
763
|
+
expect(grouped.size).toBe(2);
|
|
764
|
+
const fruits = grouped.get('fruit');
|
|
765
|
+
const vegetables = grouped.get('vegetable');
|
|
766
|
+
|
|
767
|
+
expect(Optional.isSome(fruits)).toBe(true);
|
|
768
|
+
expect(Optional.isSome(vegetables)).toBe(true);
|
|
769
|
+
|
|
770
|
+
if (Optional.isSome(fruits)) {
|
|
771
|
+
expect(fruits.value).toHaveLength(2);
|
|
772
|
+
expect(fruits.value[0]?.name).toBe('apple');
|
|
773
|
+
expect(fruits.value[1]?.name).toBe('banana');
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
if (Optional.isSome(vegetables)) {
|
|
777
|
+
expect(vegetables.value).toHaveLength(1);
|
|
778
|
+
expect(vegetables.value[0]?.name).toBe('carrot');
|
|
779
|
+
}
|
|
780
|
+
});
|
|
781
|
+
|
|
782
|
+
test('should work with numeric keys', () => {
|
|
783
|
+
const numbers = [1, 2, 3, 4, 5, 6];
|
|
784
|
+
const grouped = groupBy(numbers, (n) => n % 2);
|
|
785
|
+
|
|
786
|
+
expect(grouped.size).toBe(2);
|
|
787
|
+
const evens = grouped.get(0);
|
|
788
|
+
const odds = grouped.get(1);
|
|
789
|
+
|
|
790
|
+
if (Optional.isSome(evens)) {
|
|
791
|
+
expect(evens.value).toStrictEqual([2, 4, 6]);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (Optional.isSome(odds)) {
|
|
795
|
+
expect(odds.value).toStrictEqual([1, 3, 5]);
|
|
796
|
+
}
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
test('should work with empty array', () => {
|
|
800
|
+
const empty: readonly number[] = [];
|
|
801
|
+
const grouped = groupBy(empty, (n) => n % 2);
|
|
802
|
+
expect(grouped.size).toBe(0);
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
test('should handle all elements in same group', () => {
|
|
806
|
+
const array = [1, 2, 3, 4];
|
|
807
|
+
const grouped = groupBy(array, () => 'all');
|
|
808
|
+
|
|
809
|
+
expect(grouped.size).toBe(1);
|
|
810
|
+
const all = grouped.get('all');
|
|
811
|
+
|
|
812
|
+
if (Optional.isSome(all)) {
|
|
813
|
+
expect(all.value).toStrictEqual([1, 2, 3, 4]);
|
|
814
|
+
}
|
|
815
|
+
});
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
describe('zip', () => {
|
|
819
|
+
{
|
|
820
|
+
const xs = [1, 2, 3] as const;
|
|
821
|
+
const ys = [4, 5, 6] as const;
|
|
822
|
+
const zipped = zip(xs, ys);
|
|
823
|
+
|
|
824
|
+
expectType<
|
|
825
|
+
typeof zipped,
|
|
826
|
+
readonly [readonly [1, 4], readonly [2, 5], readonly [3, 6]]
|
|
827
|
+
>('=');
|
|
828
|
+
|
|
829
|
+
test('case 1', () => {
|
|
830
|
+
expect(zipped).toStrictEqual([
|
|
831
|
+
[1, 4],
|
|
832
|
+
[2, 5],
|
|
833
|
+
[3, 6],
|
|
834
|
+
]);
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
{
|
|
838
|
+
const xs: readonly number[] = [1, 2, 3];
|
|
839
|
+
const ys: readonly number[] = [4];
|
|
840
|
+
const zipped = zip(xs, ys);
|
|
841
|
+
|
|
842
|
+
expectType<typeof zipped, readonly (readonly [number, number])[]>('=');
|
|
843
|
+
|
|
844
|
+
test('case 2', () => {
|
|
845
|
+
expect(zipped).toStrictEqual([[1, 4]]);
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
{
|
|
849
|
+
const xs = [1] as const;
|
|
850
|
+
const ys: readonly number[] = [4, 5, 6];
|
|
851
|
+
const zipped = zip(xs, ys);
|
|
852
|
+
|
|
853
|
+
expectType<typeof zipped, readonly [readonly [1, number]]>('=');
|
|
854
|
+
|
|
855
|
+
test('case 3', () => {
|
|
856
|
+
expect(zipped).toStrictEqual([[1, 4]]);
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// testArrayEquality({
|
|
861
|
+
// testName: 'zip',
|
|
862
|
+
// target: zip([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]),
|
|
863
|
+
// toBe: [
|
|
864
|
+
// [0, 5],
|
|
865
|
+
// [1, 6],
|
|
866
|
+
// [2, 7],
|
|
867
|
+
// [3, 8],
|
|
868
|
+
// [4, 9],
|
|
869
|
+
// ],
|
|
870
|
+
// });
|
|
871
|
+
|
|
872
|
+
// testArrayEquality({
|
|
873
|
+
// testName: 'zipArrays 2 arrays',
|
|
874
|
+
// target: zipArrays([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]),
|
|
875
|
+
// toBe: [
|
|
876
|
+
// [0, 5],
|
|
877
|
+
// [1, 6],
|
|
878
|
+
// [2, 7],
|
|
879
|
+
// [3, 8],
|
|
880
|
+
// [4, 9],
|
|
881
|
+
// ],
|
|
882
|
+
// });
|
|
883
|
+
|
|
884
|
+
// testArrayEquality({
|
|
885
|
+
// testName: 'zipArrays 3 arrays',
|
|
886
|
+
// target: zipArrays(
|
|
887
|
+
// [0, 1, 2, 3, 4],
|
|
888
|
+
// [5, 6, 7, 8, 9, 999, 999],
|
|
889
|
+
// [10, 11, 12, 13, 14, 999]
|
|
890
|
+
// ),
|
|
891
|
+
// toBe: [
|
|
892
|
+
// [0, 5, 10],
|
|
893
|
+
// [1, 6, 11],
|
|
894
|
+
// [2, 7, 12],
|
|
895
|
+
// [3, 8, 13],
|
|
896
|
+
// [4, 9, 14],
|
|
897
|
+
// ],
|
|
898
|
+
// });
|
|
899
|
+
|
|
900
|
+
test('should zip two arrays', () => {
|
|
901
|
+
const arr1 = [1, 2, 3];
|
|
902
|
+
const arr2 = ['a', 'b', 'c'];
|
|
903
|
+
const result = zip(arr1, arr2);
|
|
904
|
+
expect(result).toStrictEqual([
|
|
905
|
+
[1, 'a'],
|
|
906
|
+
[2, 'b'],
|
|
907
|
+
[3, 'c'],
|
|
908
|
+
]);
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
test('should handle arrays of different lengths', () => {
|
|
912
|
+
const arr1 = [1, 2, 3, 4];
|
|
913
|
+
const arr2 = ['a', 'b'];
|
|
914
|
+
const result = zip(arr1, arr2);
|
|
915
|
+
expect(result).toStrictEqual([
|
|
916
|
+
[1, 'a'],
|
|
917
|
+
[2, 'b'],
|
|
918
|
+
]);
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
test('should work with empty arrays', () => {
|
|
922
|
+
const arr1: readonly number[] = [];
|
|
923
|
+
const arr2: readonly string[] = [];
|
|
924
|
+
const result = zip(arr1, arr2);
|
|
925
|
+
expect(result).toStrictEqual([]);
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
test('should handle one empty array', () => {
|
|
929
|
+
const arr1 = [1, 2, 3];
|
|
930
|
+
const arr2: readonly string[] = [];
|
|
931
|
+
const result = zip(arr1, arr2);
|
|
932
|
+
expect(result).toStrictEqual([]);
|
|
933
|
+
});
|
|
934
|
+
});
|
|
1162
935
|
});
|