type-plus 4.9.0 → 4.9.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/LICENSE +1 -1
- package/README.md +17 -16
- package/cjs/array/drop.js.map +1 -1
- package/cjs/functional/compose.js.map +1 -1
- package/cjs/object/record.js +1 -1
- package/cjs/object/record.js.map +1 -1
- package/cjs/object/split.js.map +1 -1
- package/esm/array/drop.js.map +1 -1
- package/esm/functional/compose.js.map +1 -1
- package/esm/object/record.js +1 -1
- package/esm/object/record.js.map +1 -1
- package/esm/object/split.js.map +1 -1
- package/package.json +7 -5
- package/ts/array/drop.ts +1 -1
- package/ts/functional/compose.spec.ts +1 -1
- package/ts/functional/compose.ts +2 -1
- package/ts/object/record.ts +3 -2
- package/ts/object/split.ts +2 -1
- package/ts/type-checker/.eslintrc.json +3 -1
- package/ts/type-checker/Boolean.ts +1 -1
- package/ts/types/.eslintrc.json +3 -1
- package/ts/types/Tuple.ts +50 -50
- package/ts/types/analyze.ts +10 -10
- package/ts/types/getPlainAnalysisReport.spec.ts +11 -0
- package/ts/types/getPlainAnalysisReport.ts +115 -115
- package/ts/utils/as.spec.ts +1 -0
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright
|
|
3
|
+
Copyright © 2018 Homa Wong (unional) (homawong@gmail.com)
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[![NPM version][npm-image]][npm-url]
|
|
4
4
|
[![NPM downloads][downloads-image]][downloads-url]
|
|
5
5
|
|
|
6
|
-
[![
|
|
6
|
+
[![GitHub NodeJS][github-nodejs]][github-action-url]
|
|
7
7
|
[![Codecov][codecov-image]][codecov-url]
|
|
8
8
|
|
|
9
9
|
[![Semantic Release][semantic-release-image]][semantic-release-url]
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
[![Visual Studio Code][vscode-image]][vscode-url]
|
|
12
12
|
[![Wallaby.js][wallaby-image]][wallaby-url]
|
|
13
13
|
|
|
14
|
-
Provides additional types and type adjusted utilities for [TypeScript]
|
|
14
|
+
Provides additional types and type adjusted utilities for [TypeScript].
|
|
15
15
|
|
|
16
16
|
## Feature Highlights
|
|
17
17
|
|
|
@@ -39,7 +39,7 @@ There are 5 kinds of type assertions:
|
|
|
39
39
|
- `type guard`: [User-defined type guard functions](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards) (`if (isBool(s))`) introduced in TypeScript 1.6.
|
|
40
40
|
- `assertion function`: [assertion functions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions) (`assertIsBool(a)`) introduced in TypeScript 3.7.
|
|
41
41
|
- `logical`: functions or generic types that returns `true` or `false` type to be used in type level programming.
|
|
42
|
-
- `filter`: generic
|
|
42
|
+
- `filter`: generic type that returns `never` if the test fails.
|
|
43
43
|
|
|
44
44
|
Here are the type assertions provided in `type-plus`.
|
|
45
45
|
Use the one that fits your specific needs.
|
|
@@ -175,7 +175,7 @@ You need to specify `T`.
|
|
|
175
175
|
|
|
176
176
|
✔️ `immediate`, `runtime`
|
|
177
177
|
|
|
178
|
-
It can used as type check: `isType.t<Equal<A, B>>()`,
|
|
178
|
+
It can be used as type check: `isType.t<Equal<A, B>>()`,
|
|
179
179
|
or value type check: `isType.t(valueTypeIsTrue)`.
|
|
180
180
|
It returns `true` when passes (which is the only case when used in TypeScript).
|
|
181
181
|
|
|
@@ -183,7 +183,7 @@ It returns `true` when passes (which is the only case when used in TypeScript).
|
|
|
183
183
|
|
|
184
184
|
✔️ `immediate`, `runtime`
|
|
185
185
|
|
|
186
|
-
It can used as type check: `isType.f<Equal<A, B>>()`,
|
|
186
|
+
It can be used as type check: `isType.f<Equal<A, B>>()`,
|
|
187
187
|
or value type check: `isType.f(valueTypeIsFalse)`.
|
|
188
188
|
It returns `true` when passes (which is the only case when used in TypeScript).
|
|
189
189
|
|
|
@@ -288,14 +288,14 @@ type No = IsAny<1, 'yes', 'no'> // 'no'
|
|
|
288
288
|
- `DropLast<A>`: drops the last value type of `A`.
|
|
289
289
|
- `DropMatch<A, Criteria>`: drops entries matching `Criteria` in array or tuple `A`.
|
|
290
290
|
- `DropUndefined<A>`: drop undefined entries from array of tuple `A`.
|
|
291
|
-
- `Filter<A, Criteria>`: filter the array or tuple `A`, keeping entries satisfying `Criteria`. **
|
|
291
|
+
- `Filter<A, Criteria>`: filter the array or tuple `A`, keeping entries satisfying `Criteria`. **Deprecated. Renaming to `KeepMatch`**
|
|
292
292
|
- `FindFirst<A, Criteria>`: gets the first type satisfying `Criteria`.
|
|
293
293
|
- `FindLast<A, Criteria>`: gets the last type satisfying `Criteria`.
|
|
294
294
|
- `Head<A>`: gets the first entry in the array.
|
|
295
295
|
- `IntersectOfProps<A, K>`: gets the intersect of `A[K]` types (deprecate `MapToProp`)
|
|
296
296
|
- `IsArray<T>`: `logical` predicate for `Array`.
|
|
297
297
|
- `KeepMatch<A, Criteria>`: keeps entries satisfying `Criteria` in array or tuple `A`.
|
|
298
|
-
- `Last<A>`: gets the last type of
|
|
298
|
+
- `Last<A>`: gets the last type of array or tuple.
|
|
299
299
|
- `literalArray(...entries)`: return an array whose items are restricted to the provided literals.
|
|
300
300
|
- `PadLeft<A, Total, PadWith>`: pads `A` with `PadWith` if the length of `A` is less than `L`.
|
|
301
301
|
- `reduceWhile()`: `reduce()` with predicate for early termination. \
|
|
@@ -319,7 +319,7 @@ type No = IsAny<1, 'yes', 'no'> // 'no'
|
|
|
319
319
|
- `JSONObject`: JSON object
|
|
320
320
|
- `JSONArray`: JSON array
|
|
321
321
|
- `JSONTypes`: all JSON compatible types.
|
|
322
|
-
- `JSONTypes.get<T>(obj, ...props)`: get a cast value in
|
|
322
|
+
- `JSONTypes.get<T>(obj, ...props)`: get a cast value in JSON
|
|
323
323
|
|
|
324
324
|
```ts
|
|
325
325
|
import { JSONTypes } from 'type-plus'
|
|
@@ -341,7 +341,7 @@ JSONTypes.get<string>(someJson, 'a', 'b', 1, 'c') // miku
|
|
|
341
341
|
- `mapKey()`: type adjusted map by key.
|
|
342
342
|
- `reduceByKey()`: type adjusted reduce by key.
|
|
343
343
|
- `someKey()`: type adjusted some by key.
|
|
344
|
-
- `SpreadRecord<A, B>`: type for `{...a, ...b}` when both `a` and `b` are `Record
|
|
344
|
+
- `SpreadRecord<A, B>`: type for `{...a, ...b}` when both `a` and `b` are `Record`\
|
|
345
345
|
for array, just do `[...A, ...B]`.
|
|
346
346
|
|
|
347
347
|
### Promise function
|
|
@@ -418,7 +418,7 @@ So you may encounter some weird behavior if your logic is complex.
|
|
|
418
418
|
- `Max<A, B, Fail=never>`: `max(A, B)`, for whole number, `Fail` otherwise.
|
|
419
419
|
- `GreaterThan<A, B, Fail=never>`: `A > B` for whole numbers, `Fail` otherwise.
|
|
420
420
|
|
|
421
|
-
####
|
|
421
|
+
#### Arithmetic
|
|
422
422
|
|
|
423
423
|
- `Add<A, B, Fail=never>`: `A + B` for positive and whole numbers, `Fail` otherwise.
|
|
424
424
|
- `Subtract<A, B, Fail=never>`: `A - B` for positive and whole numbers, `Fail` otherwise.
|
|
@@ -433,10 +433,10 @@ So you may encounter some weird behavior if your logic is complex.
|
|
|
433
433
|
- `hasKey()`: function of `HasKey`.
|
|
434
434
|
- `hasProperty(value, prop)`: assert `value` has property `prop`. This will pick the correct union type.
|
|
435
435
|
- `isConstructor(subject)`: type guard `subject` is a constructor.
|
|
436
|
-
- `isSystemError(code, err)`: type guard `err` with
|
|
436
|
+
- `isSystemError(code, err)`: type guard `err` with NodeJS error code.
|
|
437
437
|
- `omit(obj, ...props)`: omit properties from `obj`.
|
|
438
438
|
- `pick(obj, ...props)`: pick properties from `obj`.
|
|
439
|
-
- `record<K, V>(value?)`:
|
|
439
|
+
- `record<K, V>(value?)`: create a `Record<K, V>` without extra object prototype.
|
|
440
440
|
- `required(...)`: merge options and removing `Partial<T>`. From [`unpartial`](https://github.com/unional/unpartial)
|
|
441
441
|
- `requiredDeep(...)`: merge options deeply and removing `Partial<T>`. From [`unpartial`](https://github.com/unional/unpartial)
|
|
442
442
|
- `split(target, ...splitters)`: split one object into multiple objects.
|
|
@@ -528,8 +528,8 @@ nominalMatch(b1, b2) // false
|
|
|
528
528
|
|
|
529
529
|
## Attribution
|
|
530
530
|
|
|
531
|
-
Some
|
|
532
|
-
I merely adding them in and maybe making some adjustments.
|
|
531
|
+
Some code in this library is created by other people in the TypeScript community.
|
|
532
|
+
I'm merely adding them in and maybe making some adjustments.
|
|
533
533
|
Whenever possible, I add attribution to the person who created those **codes** in the file.
|
|
534
534
|
|
|
535
535
|
## Similar projects
|
|
@@ -539,7 +539,7 @@ Whenever possible, I add attribution to the person who created those **codes** i
|
|
|
539
539
|
- [`type-fest`](https://github.com/sindresorhus/type-fest), a collection of essential TypeScript types.
|
|
540
540
|
- [`type-zoo`](https://github.com/pelotom/type-zoo), a modest type lib usable today.
|
|
541
541
|
- [`typepark`](https://github.com/kgtkr/typepark), a new type collection offering tuple manipulation and `Pipe`.
|
|
542
|
-
- [`typelevel-ts`](https://github.com/gcanti/typelevel-ts), a type lib by [@gcanti](https://github.com/gcanti), author of several FP
|
|
542
|
+
- [`typelevel-ts`](https://github.com/gcanti/typelevel-ts), a type lib by [@gcanti](https://github.com/gcanti), author of several FP libraries in TS.
|
|
543
543
|
- [`typical`](https://github.com/KiaraGrouwstra/typical), a playground of type-level operations for TypeScript.
|
|
544
544
|
|
|
545
545
|
## Contribute
|
|
@@ -563,12 +563,13 @@ git push
|
|
|
563
563
|
[codecov-url]: https://codecov.io/gh/unional/type-plus
|
|
564
564
|
[downloads-image]: https://img.shields.io/npm/dm/type-plus.svg?style=flat
|
|
565
565
|
[downloads-url]: https://npmjs.org/package/type-plus
|
|
566
|
-
[github-nodejs]: https://github.com/unional/type-plus/workflows/nodejs/badge.svg
|
|
567
566
|
[github-action-url]: https://github.com/unional/type-plus/actions
|
|
567
|
+
[github-nodejs]: https://github.com/unional/type-plus/workflows/nodejs/badge.svg
|
|
568
568
|
[npm-image]: https://img.shields.io/npm/v/type-plus.svg?style=flat
|
|
569
569
|
[npm-url]: https://npmjs.org/package/type-plus
|
|
570
570
|
[semantic-release-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
|
|
571
571
|
[semantic-release-url]: https://github.com/semantic-release/semantic-release
|
|
572
|
+
[TypeScript]: https://www.typescriptlang.org
|
|
572
573
|
[vscode-image]: https://img.shields.io/badge/vscode-ready-green.svg
|
|
573
574
|
[vscode-url]: https://code.visualstudio.com/
|
|
574
575
|
[wallaby-image]: https://img.shields.io/badge/wallaby.js-configured-green.svg
|
package/cjs/array/drop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drop.js","sourceRoot":"","sources":["../../ts/array/drop.ts"],"names":[],"mappings":";;;AAqEA,SAAgB,IAAI,CAAoC,KAAQ,EAAE,KAAQ;IACxE,OAAO,KAAK,CAAC,MAAM,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,KAAK,KAAK,EAAX,CAAW,
|
|
1
|
+
{"version":3,"file":"drop.js","sourceRoot":"","sources":["../../ts/array/drop.ts"],"names":[],"mappings":";;;AAqEA,SAAgB,IAAI,CAAoC,KAAQ,EAAE,KAAQ;IACxE,OAAO,KAAK,CAAC,MAAM,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,KAAK,KAAK,EAAX,CAAW,CAAoB,CAAA;AAC1D,CAAC;AAFD,oBAEC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../ts/functional/compose.ts"],"names":[],"mappings":";;;AAMA,SAAgB,OAAO;IAA2B,aAAU;SAAV,UAAU,EAAV,qBAAU,EAAV,IAAU;QAAV,wBAAU;;
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../ts/functional/compose.ts"],"names":[],"mappings":";;;AAMA,SAAgB,OAAO;IAA2B,aAAU;SAAV,UAAU,EAAV,qBAAU,EAAV,IAAU;QAAV,wBAAU;;IAE1D,OAAO;QAAC,cAAc;aAAd,UAAc,EAAd,qBAAc,EAAd,IAAc;YAAd,yBAAc;;QAAK,OAAA,GAAG,CAAC,MAAM,CAAC,UAAC,IAAI,EAAE,EAAE,IAAK,OAAA,CAAC,EAAE,eAAI,IAAI,EAAE,EAAb,CAAa,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAAhD,CAAgD,CAAA;AAC7E,CAAC;AAHD,0BAGC"}
|
package/cjs/object/record.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.record = void 0;
|
|
4
4
|
function record(value) {
|
|
5
5
|
var r = Object.create(null);
|
|
6
|
-
return value ? Object.assign(r, value) : r;
|
|
6
|
+
return (value ? Object.assign(r, value) : r);
|
|
7
7
|
}
|
|
8
8
|
exports.record = record;
|
|
9
9
|
//# sourceMappingURL=record.js.map
|
package/cjs/object/record.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../ts/object/record.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../ts/object/record.ts"],"names":[],"mappings":";;;AAOA,SAAgB,MAAM,CAAwB,KAAoB;IAChE,IAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAc,CAAA;IAC1C,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAwB,CAAA;AACrE,CAAC;AAHD,wBAGC"}
|
package/cjs/object/split.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split.js","sourceRoot":"","sources":["../../ts/object/split.ts"],"names":[],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"split.js","sourceRoot":"","sources":["../../ts/object/split.ts"],"names":[],"mappings":";;;;;;;;;;;;AAGA,yCAAyC;AA+LzC,SAAgB,KAAK,CAAC,MAAiB;IAAE,mBAAyB;SAAzB,UAAyB,EAAzB,qBAAyB,EAAzB,IAAyB;QAAzB,kCAAyB;;IAChE,IAAM,MAAM,GAAc,EAAE,CAAA;IAC5B,IAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,IAAA,uBAAW,EACtC,CAAC,EACD,UAAC,CAAC,EAAE,CAAC,YAAK,OAAA,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,MAAA,MAAM,CAAC,CAAC,CAAC,mCAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA,EAAA,EACzD,EAAe,CAAC,EAHW,CAGX,CAAC,CAAA;IACnB,IAAM,CAAC,GAAG,IAAA,uBAAW,EAAC,MAAM,EAAE,UAAC,CAAC,EAAE,CAAC,IAAK,OAAA,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAArC,CAAqC,EAAE,EAAe,CAAC,CAAA;IAC/F,uCAAW,CAAC,UAAE,CAAC,UAAC;AAClB,CAAC;AARD,sBAQC"}
|
package/esm/array/drop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drop.js","sourceRoot":"","sources":["../../ts/array/drop.ts"],"names":[],"mappings":"AAqEA,MAAM,UAAU,IAAI,CAAoC,KAAQ,EAAE,KAAQ;IACxE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"drop.js","sourceRoot":"","sources":["../../ts/array/drop.ts"],"names":[],"mappings":"AAqEA,MAAM,UAAU,IAAI,CAAoC,KAAQ,EAAE,KAAQ;IACxE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,KAAK,CAAoB,CAAA;AAC1D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../ts/functional/compose.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,OAAO,CAA2B,GAAG,GAAO;
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../ts/functional/compose.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,OAAO,CAA2B,GAAG,GAAO;IAE1D,OAAO,CAAC,GAAG,IAAW,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;AAC7E,CAAC"}
|
package/esm/object/record.js
CHANGED
package/esm/object/record.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../ts/object/record.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../ts/object/record.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,MAAM,CAAwB,KAAoB;IAChE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAc,CAAA;IAC1C,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAwB,CAAA;AACrE,CAAC"}
|
package/esm/object/split.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split.js","sourceRoot":"","sources":["../../ts/object/split.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"split.js","sourceRoot":"","sources":["../../ts/object/split.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA+LzC,MAAM,UAAU,KAAK,CAAC,MAAiB,EAAE,GAAG,SAAsB;IAChE,MAAM,MAAM,GAAc,EAAE,CAAA;IAC5B,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CACtC,CAAC,EACD,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EACzD,EAAe,CAAC,CAAC,CAAA;IACnB,MAAM,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAe,CAAC,CAAA;IAC/F,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;AAClB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "type-plus",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.1",
|
|
4
4
|
"description": "Provides additional types for TypeScript.",
|
|
5
5
|
"homepage": "https://github.com/unional/type-plus",
|
|
6
6
|
"bugs": {
|
|
@@ -63,15 +63,17 @@
|
|
|
63
63
|
"@semantic-release/changelog": "^6.0.1",
|
|
64
64
|
"@size-limit/preset-small-lib": "^7.0.8",
|
|
65
65
|
"@types/jest": "^27.4.1",
|
|
66
|
+
"@typescript-eslint/eslint-plugin": "^5.23.0",
|
|
67
|
+
"@typescript-eslint/parser": "^5.23.0",
|
|
66
68
|
"@unional/fixture": "^1.8.0",
|
|
67
69
|
"assertron": "^9.0.4",
|
|
68
70
|
"dependency-check": "^4.1.0",
|
|
69
71
|
"eslint": "^8.11.0",
|
|
70
|
-
"eslint-plugin-harmony": "^
|
|
71
|
-
"husky": "^
|
|
72
|
-
"jest": "^
|
|
72
|
+
"eslint-plugin-harmony": "^7.0.1",
|
|
73
|
+
"husky": "^8.0.0",
|
|
74
|
+
"jest": "^28.0.0",
|
|
73
75
|
"jest-progress-tracker": "^3.0.3",
|
|
74
|
-
"jest-validate": "^
|
|
76
|
+
"jest-validate": "^28.0.0",
|
|
75
77
|
"jest-watch-repeat": "^2.0.0",
|
|
76
78
|
"jest-watch-suspend": "^1.1.2",
|
|
77
79
|
"jest-watch-toggle-config": "^2.0.1",
|
package/ts/array/drop.ts
CHANGED
|
@@ -68,5 +68,5 @@ export type DropUndefined<A extends Array<any>> = DropMatch<A, undefined>
|
|
|
68
68
|
* drop a particular value from an array
|
|
69
69
|
*/
|
|
70
70
|
export function drop<A extends Readonly<Array<any>>, C>(array: A, value: C): DropMatch<A, C> {
|
|
71
|
-
return array.filter(v => v !== value) as
|
|
71
|
+
return array.filter(v => v !== value) as DropMatch<A, C>
|
|
72
72
|
}
|
package/ts/functional/compose.ts
CHANGED
|
@@ -5,5 +5,6 @@ import { AnyFunction } from '../function/AnyFunction'
|
|
|
5
5
|
* compose functions
|
|
6
6
|
*/
|
|
7
7
|
export function compose<FS extends AnyFunction[]>(...fns: FS): (...args: Parameters<Head<FS>>) => ReturnType<Last<FS>> {
|
|
8
|
-
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
9
|
+
return (...args: any[]) => fns.reduce((args, fn) => [fn(...args)], args)[0]
|
|
9
10
|
}
|
package/ts/object/record.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { KeyTypes } from 'type-plus'
|
|
2
2
|
import { Widen } from '../utils'
|
|
3
|
+
import { AnyRecord } from './AnyRecord'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Creates a `Record<Key, Value>`
|
|
6
7
|
*/
|
|
7
8
|
export function record<K extends KeyTypes, V>(value?: Record<K, V>): Record<Widen<K>, V> {
|
|
8
|
-
const r = Object.create(null)
|
|
9
|
-
return value ? Object.assign(r, value) : r
|
|
9
|
+
const r = Object.create(null) as AnyRecord
|
|
10
|
+
return (value ? Object.assign(r, value) : r) as Record<Widen<K>, V>
|
|
10
11
|
}
|
package/ts/object/split.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
1
2
|
import { AnyRecord } from './AnyRecord'
|
|
2
3
|
import { Omit } from './omit'
|
|
3
4
|
import { reduceByKey } from './reduceKey'
|
|
@@ -195,7 +196,7 @@ export function split(target: AnyRecord, ...splitters: AnyRecord[]): AnyRecord[]
|
|
|
195
196
|
const keyMap: AnyRecord = {}
|
|
196
197
|
const s = splitters.map(s => reduceByKey(
|
|
197
198
|
s,
|
|
198
|
-
(p, k) => (keyMap[k] = true, p[k] = target[k]
|
|
199
|
+
(p, k) => (keyMap[k] = true, p[k] = target[k] ?? s[k], p),
|
|
199
200
|
{} as AnyRecord))
|
|
200
201
|
const r = reduceByKey(target, (p, k) => keyMap[k] ? p : (p[k] = target[k], p), {} as AnyRecord)
|
|
201
202
|
return [...s, r]
|
|
@@ -30,5 +30,5 @@ export const BooleanSpec: TypeSpec<Type<'boolean', boolean>> = {
|
|
|
30
30
|
return value === actual ? { type: 'boolean', value } : { type: 'boolean', value, fail: true }
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
-
toNative(value: any): true { return value
|
|
33
|
+
toNative(value: any): true { return value }
|
|
34
34
|
}
|
package/ts/types/.eslintrc.json
CHANGED
package/ts/types/Tuple.ts
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import { TypeAnalysis, Type } from './types'
|
|
2
|
-
import { AllType } from './AllType'
|
|
3
|
-
import { undef, Undefined } from './Undefined'
|
|
4
|
-
import { union, Union } from './Union'
|
|
5
|
-
import { Tail } from '../array'
|
|
6
|
-
|
|
7
|
-
export type Tuple<Values extends AllType[] = any[]> = Type<'tuple', Values>
|
|
8
|
-
|
|
9
|
-
export namespace Tuple {
|
|
10
|
-
export type Analysis<
|
|
11
|
-
Value extends AllType.PrimitiveValues | AllType.Analysis = any
|
|
12
|
-
> = TypeAnalysis<'tuple', Value[]>
|
|
13
|
-
|
|
14
|
-
export type FindByProp<
|
|
15
|
-
Tuple extends Array<{ [K in Key]: any }>,
|
|
16
|
-
Key extends string,
|
|
17
|
-
Value> = FindByProp._<Tuple, Key, Value>['result']
|
|
18
|
-
export namespace FindByProp {
|
|
19
|
-
export type _<Tuple extends Array<{ [K in Key]: any }>, Key extends string, Value> = Tuple['length'] extends 0
|
|
20
|
-
? { result: never }
|
|
21
|
-
: { result: Value extends Tuple[0][Key] ? Tuple[0] : _<Tail<Tuple>, Key, Value>['result'] }
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Creates a tuple type.
|
|
27
|
-
*/
|
|
28
|
-
function create<Value extends AllType, Values extends AllType[]>(
|
|
29
|
-
value: Value,
|
|
30
|
-
...values: Values
|
|
31
|
-
): Tuple<[Value, ...Values]> {
|
|
32
|
-
return {
|
|
33
|
-
type: 'tuple',
|
|
34
|
-
value: [value, ...values]
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
export const tuple = {
|
|
38
|
-
create,
|
|
39
|
-
optional: {
|
|
40
|
-
/**
|
|
41
|
-
* Creates an optional tuple type.
|
|
42
|
-
*/
|
|
43
|
-
create<Value extends AllType, Values extends AllType[]>(
|
|
44
|
-
value: Value,
|
|
45
|
-
...values: Values
|
|
46
|
-
): Union<[Tuple<[Value, ...Values]>, Undefined]> {
|
|
47
|
-
return union.create(create(value, ...values), undef)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
1
|
+
import { TypeAnalysis, Type } from './types'
|
|
2
|
+
import { AllType } from './AllType'
|
|
3
|
+
import { undef, Undefined } from './Undefined'
|
|
4
|
+
import { union, Union } from './Union'
|
|
5
|
+
import { Tail } from '../array'
|
|
6
|
+
|
|
7
|
+
export type Tuple<Values extends AllType[] = any[]> = Type<'tuple', Values>
|
|
8
|
+
|
|
9
|
+
export namespace Tuple {
|
|
10
|
+
export type Analysis<
|
|
11
|
+
Value extends AllType.PrimitiveValues | AllType.Analysis = any
|
|
12
|
+
> = TypeAnalysis<'tuple', Value[]>
|
|
13
|
+
|
|
14
|
+
export type FindByProp<
|
|
15
|
+
Tuple extends Array<{ [K in Key]: any }>,
|
|
16
|
+
Key extends string,
|
|
17
|
+
Value> = FindByProp._<Tuple, Key, Value>['result']
|
|
18
|
+
export namespace FindByProp {
|
|
19
|
+
export type _<Tuple extends Array<{ [K in Key]: any }>, Key extends string, Value> = Tuple['length'] extends 0
|
|
20
|
+
? { result: never }
|
|
21
|
+
: { result: Value extends Tuple[0][Key] ? Tuple[0] : _<Tail<Tuple>, Key, Value>['result'] }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates a tuple type.
|
|
27
|
+
*/
|
|
28
|
+
function create<Value extends AllType, Values extends AllType[]>(
|
|
29
|
+
value: Value,
|
|
30
|
+
...values: Values
|
|
31
|
+
): Tuple<[Value, ...Values]> {
|
|
32
|
+
return {
|
|
33
|
+
type: 'tuple',
|
|
34
|
+
value: [value, ...values]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export const tuple = {
|
|
38
|
+
create,
|
|
39
|
+
optional: {
|
|
40
|
+
/**
|
|
41
|
+
* Creates an optional tuple type.
|
|
42
|
+
*/
|
|
43
|
+
create<Value extends AllType, Values extends AllType[]>(
|
|
44
|
+
value: Value,
|
|
45
|
+
...values: Values
|
|
46
|
+
): Union<[Tuple<[Value, ...Values]>, Undefined]> {
|
|
47
|
+
return union.create(create(value, ...values), undef)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
package/ts/types/analyze.ts
CHANGED
|
@@ -36,15 +36,15 @@ export function analyzeInternal(options: analyze.Options, type: AllType, actual:
|
|
|
36
36
|
return typeof actual === t ? ok(type) : fail(t)
|
|
37
37
|
case 'null':
|
|
38
38
|
return actual === null ? ok(type) : fail(t)
|
|
39
|
-
case 'boolean': return analyzeBoolean(type
|
|
40
|
-
case 'number': return analyzeType(number, type
|
|
41
|
-
case 'string': return analyzeType(string, type
|
|
39
|
+
case 'boolean': return analyzeBoolean(type, actual)
|
|
40
|
+
case 'number': return analyzeType(number, type, actual)
|
|
41
|
+
case 'string': return analyzeType(string, type, actual)
|
|
42
42
|
// case 'bigint': return analyzeType(bigint, type as BigInt, actual)
|
|
43
|
-
case 'object': return analyzeObject(options, type
|
|
44
|
-
case 'record': return analyzeRecord(options, type
|
|
45
|
-
case 'array': return analyzeArray(options, type
|
|
46
|
-
case 'tuple': return analyzeTuple(options, type
|
|
47
|
-
case 'union': return analyzeUnion(options, type
|
|
43
|
+
case 'object': return analyzeObject(options, type, actual)
|
|
44
|
+
case 'record': return analyzeRecord(options, type, actual)
|
|
45
|
+
case 'array': return analyzeArray(options, type, actual)
|
|
46
|
+
case 'tuple': return analyzeTuple(options, type, actual)
|
|
47
|
+
case 'union': return analyzeUnion(options, type, actual)
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -63,7 +63,7 @@ function analyzeType(
|
|
|
63
63
|
type: Type<any, any>,
|
|
64
64
|
actual: unknown
|
|
65
65
|
) {
|
|
66
|
-
const value = type
|
|
66
|
+
const value = type.value
|
|
67
67
|
return typeof actual === baseType['type'] && (type === baseType || actual === value)
|
|
68
68
|
? ok(type)
|
|
69
69
|
: fail(type['type'], type['value'])
|
|
@@ -80,7 +80,7 @@ function analyzeArray(options: analyze.Options, type: ArrayType<AllType>, actual
|
|
|
80
80
|
if (!Array.isArray(actual)) return fail('array', subType ? ok(subType) : undefined)
|
|
81
81
|
if (subType === undefined) return ok(type)
|
|
82
82
|
|
|
83
|
-
const r = actual.reduce((p, a, i) => {
|
|
83
|
+
const r = actual.reduce((p: { keys: number[], actual: any[], value: any }, a, i) => {
|
|
84
84
|
const r = analyzeInternal(options, subType, a)
|
|
85
85
|
if (r.fail) {
|
|
86
86
|
p.value = r.value
|
|
@@ -237,6 +237,17 @@ describe('tuple', () => {
|
|
|
237
237
|
].join('\n')
|
|
238
238
|
)
|
|
239
239
|
})
|
|
240
|
+
test('strict with more than 2 extra', () => {
|
|
241
|
+
assertReportEquals(
|
|
242
|
+
strict,
|
|
243
|
+
T.tuple.create(T.null, T.number),
|
|
244
|
+
[null, 1, 'a', false, true],
|
|
245
|
+
[
|
|
246
|
+
`subject expects to be strictly [null,number] but is actually [null, 1, 'a', false, true]`,
|
|
247
|
+
`indices 2..4 should not contain any value`
|
|
248
|
+
].join('\n')
|
|
249
|
+
)
|
|
250
|
+
})
|
|
240
251
|
})
|
|
241
252
|
describe('object', () => {
|
|
242
253
|
test('not object', () => {
|
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
import { tersify } from 'tersify'
|
|
2
|
-
import { reduceByKey } from '../object'
|
|
3
|
-
import { AllType } from './AllType'
|
|
4
|
-
import { analyze } from './analyze'
|
|
5
|
-
|
|
6
|
-
export function getPlainAnalysisReport(analysisResult: analyze.Result) {
|
|
7
|
-
if (!analysisResult.analysis.fail) {
|
|
8
|
-
return `The subject${analysisResult.options.strict ? ' strictly' : ''} satisfies type ${formatAnalysis(analysisResult.analysis)}`
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return toViolations(analysisResult.options, [], analysisResult.actual, analysisResult.analysis).join('\n')
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function formatAnalysis(a: AllType.Analysis) {
|
|
15
|
-
return a.type
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function toViolations(options: analyze.Options, path: Array<string | number>, actual: any, analysis: AllType.Analysis): string[] {
|
|
19
|
-
const clause = options.strict ? `expects to be strictly` : `expects to be`
|
|
20
|
-
const violations = [`${formatPath(path)} ${clause} ${formatType(analysis)} but is actually ${tersify(actual)}`]
|
|
21
|
-
|
|
22
|
-
switch (analysis.type) {
|
|
23
|
-
case 'tuple': {
|
|
24
|
-
if (options.strict && analysis.value!.length < actual.length) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
case '
|
|
73
|
-
case '
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
case '
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
p
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return
|
|
115
|
-
}
|
|
1
|
+
import { tersify } from 'tersify'
|
|
2
|
+
import { reduceByKey } from '../object'
|
|
3
|
+
import { AllType } from './AllType'
|
|
4
|
+
import { analyze } from './analyze'
|
|
5
|
+
|
|
6
|
+
export function getPlainAnalysisReport(analysisResult: analyze.Result) {
|
|
7
|
+
if (!analysisResult.analysis.fail) {
|
|
8
|
+
return `The subject${analysisResult.options.strict ? ' strictly' : ''} satisfies type ${formatAnalysis(analysisResult.analysis)}`
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return toViolations(analysisResult.options, [], analysisResult.actual, analysisResult.analysis).join('\n')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function formatAnalysis(a: AllType.Analysis) {
|
|
15
|
+
return a.type
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function toViolations(options: analyze.Options, path: Array<string | number>, actual: any, analysis: AllType.Analysis): string[] {
|
|
19
|
+
const clause = options.strict ? `expects to be strictly` : `expects to be`
|
|
20
|
+
const violations = [`${formatPath(path)} ${clause} ${formatType(analysis)} but is actually ${tersify(actual)}`]
|
|
21
|
+
|
|
22
|
+
switch (analysis.type) {
|
|
23
|
+
case 'tuple': {
|
|
24
|
+
if (options.strict && analysis.value!.length < actual.length) {
|
|
25
|
+
violations.push(`${range(analysis.value!.length, actual.length)} should not contain any value`)
|
|
26
|
+
}
|
|
27
|
+
const v2 = analysis.value!.reduce((p: string[], a, i) => {
|
|
28
|
+
if (a.fail) p.push(...toViolations(options, [...path, i], actual[i], a))
|
|
29
|
+
return p
|
|
30
|
+
}, [])
|
|
31
|
+
if (v2.length > 0) violations.push(...v2)
|
|
32
|
+
break
|
|
33
|
+
}
|
|
34
|
+
case 'object':
|
|
35
|
+
if (analysis.value) {
|
|
36
|
+
const typeKeys = Object.keys(analysis.value)
|
|
37
|
+
const actualKeys = Object.keys(actual)
|
|
38
|
+
if (options.strict) {
|
|
39
|
+
const extraKeys = actualKeys.filter(k => typeKeys.indexOf(k) === -1)
|
|
40
|
+
const index = extraKeys.length === 1 ? 'property' : 'properties'
|
|
41
|
+
violations.push(`${index} ${extraKeys.join(',')} should not contain any value`)
|
|
42
|
+
}
|
|
43
|
+
const propViolations = typeKeys.reduce((p, k) => {
|
|
44
|
+
const a = analysis.value![k]
|
|
45
|
+
if (a.fail) p.push(...toViolations(options, [...path, k], actual[k], a))
|
|
46
|
+
return p
|
|
47
|
+
}, [] as string[])
|
|
48
|
+
if (propViolations.length > 0) violations.push(...propViolations)
|
|
49
|
+
}
|
|
50
|
+
break
|
|
51
|
+
}
|
|
52
|
+
return violations
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function formatPath(path: Array<string | number>) {
|
|
56
|
+
return path.length === 0 ? 'subject' : `subject${path.map(p => toAccessor(p)).join('')}`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function toAccessor(p: string | number) {
|
|
60
|
+
if (typeof p === 'number') return `[${p}]`
|
|
61
|
+
if (p.indexOf('-') >= 0) return `['${p}']`
|
|
62
|
+
return `.${p}`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function toProp(p: string) {
|
|
66
|
+
return p.indexOf('-') >= 0 ? `'${p}'` : p
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function formatType(e: AllType.Analysis): string {
|
|
70
|
+
switch (e.type) {
|
|
71
|
+
case 'undefined':
|
|
72
|
+
case 'null':
|
|
73
|
+
case 'symbol':
|
|
74
|
+
// case 'never':
|
|
75
|
+
return e.type
|
|
76
|
+
case 'boolean':
|
|
77
|
+
case 'number':
|
|
78
|
+
// case 'bigint':
|
|
79
|
+
return e.value === undefined ? e.type : String(e.value)
|
|
80
|
+
case 'string':
|
|
81
|
+
return e.value === undefined ? e.type : `'${e.value}'`
|
|
82
|
+
case 'array':
|
|
83
|
+
return e.value === undefined ? 'Array<any>' : `Array<${formatType(e.value)}>`
|
|
84
|
+
case 'tuple':
|
|
85
|
+
return `[${formatExpectations(e.value as AllType.Analysis[])}]`
|
|
86
|
+
case 'object':
|
|
87
|
+
return e.value === undefined ? e.type
|
|
88
|
+
: `{ ${reduceByKey(
|
|
89
|
+
e.value,
|
|
90
|
+
(p, k) => {
|
|
91
|
+
p.push(`${toProp(k)}: ${formatType((e.value as any)[k])}`)
|
|
92
|
+
return p
|
|
93
|
+
},
|
|
94
|
+
[] as string[]
|
|
95
|
+
).join(', ')} }`
|
|
96
|
+
case 'record':
|
|
97
|
+
return `Record<string, ${formatType(e.value)}>`
|
|
98
|
+
case 'union':
|
|
99
|
+
return `(${formatExpectations(e.value as AllType.Analysis[], ' | ')})`
|
|
100
|
+
// istanbul ignore next
|
|
101
|
+
default:
|
|
102
|
+
return `report not expected: ${e.type}`
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function formatExpectations(es: AllType.Analysis[], sep = ',') {
|
|
107
|
+
return es.map(formatType).join(sep)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function range(start: number, end: number) {
|
|
111
|
+
const diff = end - start
|
|
112
|
+
if (diff === 1) return `index ${start}`
|
|
113
|
+
if (diff === 2) return `indices ${start},${end - 1}`
|
|
114
|
+
return `indices ${start}..${end - 1}`
|
|
115
|
+
}
|
package/ts/utils/as.spec.ts
CHANGED