type-plus 4.6.3 → 4.8.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 CHANGED
@@ -427,6 +427,7 @@ So you may encounter some weird behavior if your logic is complex.
427
427
 
428
428
  ### Utility Functions
429
429
 
430
+ - `amend(subject)...`: amend subject as union or intersect of `T`.
430
431
  - `facade(subject, ...props)`: create a facade of `subject`.
431
432
  - `getField(subject, key, defaultValue)`: get a field from a subject. Works against nullable and optional subject.
432
433
  - `hasKey()`: function of `HasKey`.
@@ -440,6 +441,7 @@ So you may encounter some weird behavior if your logic is complex.
440
441
  - `requiredDeep(...)`: merge options deeply and removing `Partial<T>`. From [`unpartial`](https://github.com/unional/unpartial)
441
442
  - `split(target, ...splitters)`: split one object into multiple objects.
442
443
  - `stub<T>(value)`: stub a particular type `T`.
444
+ - `stub.build<T>(init?)`: build a stub for particular type `T`.
443
445
  - `typeOverrideIncompatible<T>()`: override only the incompatible portion between two types.
444
446
 
445
447
  ```ts
@@ -4,7 +4,7 @@ declare type Splitter<T extends AnyRecord> = Partial<{
4
4
  [k in keyof T]: T[k] | undefined;
5
5
  }>;
6
6
  export declare type Split<T extends AnyRecord, S extends AnyRecord> = {
7
- [k in keyof S]: S[k] extends undefined ? T[k] : NonNullable<T[k]> | S[k];
7
+ [k in keyof S]-?: S[k] extends undefined ? T[k] : NonNullable<T[k]> | S[k];
8
8
  };
9
9
  export declare function split<T extends AnyRecord, S1 extends Splitter<T>>(target: T, split1: S1): [
10
10
  Split<T, S1>,
@@ -4,3 +4,6 @@ export declare namespace stub {
4
4
  type Param<T> = T extends AnyFunction ? T : RecursivePartial<T>;
5
5
  }
6
6
  export declare function stub<T>(stub?: stub.Param<T>): T;
7
+ export declare namespace stub {
8
+ var build: <T>(init?: Param<T> | undefined) => (value?: Param<T> | undefined) => T;
9
+ }
@@ -1,8 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.stub = void 0;
4
+ var unpartial_1 = require("unpartial");
4
5
  function stub(stub) {
5
6
  return stub;
6
7
  }
7
8
  exports.stub = stub;
9
+ stub.build = function build(init) {
10
+ return function (value) {
11
+ return init
12
+ ? stub((0, unpartial_1.requiredDeep)(init, value))
13
+ : stub(value);
14
+ };
15
+ };
8
16
  //# sourceMappingURL=stub.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stub.js","sourceRoot":"","sources":["../../ts/testing/stub.ts"],"names":[],"mappings":";;;AAOA,SAAgB,IAAI,CAAI,IAAoB;IAC1C,OAAO,IAAS,CAAA;AAClB,CAAC;AAFD,oBAEC"}
1
+ {"version":3,"file":"stub.js","sourceRoot":"","sources":["../../ts/testing/stub.ts"],"names":[],"mappings":";;;AAAA,uCAAwC;AAQxC,SAAgB,IAAI,CAAI,IAAoB;IAC1C,OAAO,IAAS,CAAA;AAClB,CAAC;AAFD,oBAEC;AAKD,IAAI,CAAC,KAAK,GAAG,SAAS,KAAK,CAAI,IAAoB;IACjD,OAAO,UAAU,KAAqB;QACpC,OAAO,IAAI;YACT,CAAC,CAAC,IAAI,CAAI,IAAA,wBAAY,EAAC,IAAW,EAAE,KAAY,CAAQ,CAAC;YACzD,CAAC,CAAC,IAAI,CAAI,KAAK,CAAC,CAAA;IACpB,CAAC,CAAA;AACH,CAAC,CAAA"}
package/cjs/utils/as.d.ts CHANGED
@@ -1,2 +1,6 @@
1
1
  export declare function as<T>(subject: unknown): T;
2
2
  export declare function asAny(subject: unknown): any;
3
+ export declare function amend<S>(subject: S): {
4
+ union<T>(): T & S;
5
+ intersect<T_1>(): S | T_1;
6
+ };
package/cjs/utils/as.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.asAny = exports.as = void 0;
3
+ exports.amend = exports.asAny = exports.as = void 0;
4
4
  function as(subject) {
5
5
  return subject;
6
6
  }
@@ -9,4 +9,11 @@ function asAny(subject) {
9
9
  return subject;
10
10
  }
11
11
  exports.asAny = asAny;
12
+ function amend(subject) {
13
+ return {
14
+ union: function () { return subject; },
15
+ intersect: function () { return subject; }
16
+ };
17
+ }
18
+ exports.amend = amend;
12
19
  //# sourceMappingURL=as.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"as.js","sourceRoot":"","sources":["../../ts/utils/as.ts"],"names":[],"mappings":";;;AAAA,SAAgB,EAAE,CAAI,OAAgB;IACpC,OAAO,OAAY,CAAA;AACrB,CAAC;AAFD,gBAEC;AAED,SAAgB,KAAK,CAAC,OAAgB;IACpC,OAAO,OAAO,CAAA;AAChB,CAAC;AAFD,sBAEC"}
1
+ {"version":3,"file":"as.js","sourceRoot":"","sources":["../../ts/utils/as.ts"],"names":[],"mappings":";;;AAAA,SAAgB,EAAE,CAAI,OAAgB;IACpC,OAAO,OAAY,CAAA;AACrB,CAAC;AAFD,gBAEC;AAED,SAAgB,KAAK,CAAC,OAAgB;IACpC,OAAO,OAAO,CAAA;AAChB,CAAC;AAFD,sBAEC;AAKD,SAAgB,KAAK,CAAI,OAAU;IACjC,OAAO;QACL,KAAK,EAAL,cAAoB,OAAO,OAAgB,CAAA,CAAC,CAAC;QAC7C,SAAS,EAAT,cAAwB,OAAO,OAAgB,CAAA,CAAC,CAAC;KAClD,CAAA;AACH,CAAC;AALD,sBAKC"}
@@ -1,4 +1,12 @@
1
+ import { requiredDeep } from 'unpartial';
1
2
  export function stub(stub) {
2
3
  return stub;
3
4
  }
5
+ stub.build = function build(init) {
6
+ return function (value) {
7
+ return init
8
+ ? stub(requiredDeep(init, value))
9
+ : stub(value);
10
+ };
11
+ };
4
12
  //# sourceMappingURL=stub.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stub.js","sourceRoot":"","sources":["../../ts/testing/stub.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,IAAI,CAAI,IAAoB;IAC1C,OAAO,IAAS,CAAA;AAClB,CAAC"}
1
+ {"version":3,"file":"stub.js","sourceRoot":"","sources":["../../ts/testing/stub.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAQxC,MAAM,UAAU,IAAI,CAAI,IAAoB;IAC1C,OAAO,IAAS,CAAA;AAClB,CAAC;AAKD,IAAI,CAAC,KAAK,GAAG,SAAS,KAAK,CAAI,IAAoB;IACjD,OAAO,UAAU,KAAqB;QACpC,OAAO,IAAI;YACT,CAAC,CAAC,IAAI,CAAI,YAAY,CAAC,IAAW,EAAE,KAAY,CAAQ,CAAC;YACzD,CAAC,CAAC,IAAI,CAAI,KAAK,CAAC,CAAA;IACpB,CAAC,CAAA;AACH,CAAC,CAAA"}
package/esm/utils/as.js CHANGED
@@ -4,4 +4,10 @@ export function as(subject) {
4
4
  export function asAny(subject) {
5
5
  return subject;
6
6
  }
7
+ export function amend(subject) {
8
+ return {
9
+ union() { return subject; },
10
+ intersect() { return subject; }
11
+ };
12
+ }
7
13
  //# sourceMappingURL=as.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"as.js","sourceRoot":"","sources":["../../ts/utils/as.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,EAAE,CAAI,OAAgB;IACpC,OAAO,OAAY,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,OAAgB;IACpC,OAAO,OAAO,CAAA;AAChB,CAAC"}
1
+ {"version":3,"file":"as.js","sourceRoot":"","sources":["../../ts/utils/as.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,EAAE,CAAI,OAAgB;IACpC,OAAO,OAAY,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,OAAgB;IACpC,OAAO,OAAO,CAAA;AAChB,CAAC;AAKD,MAAM,UAAU,KAAK,CAAI,OAAU;IACjC,OAAO;QACL,KAAK,KAAe,OAAO,OAAgB,CAAA,CAAC,CAAC;QAC7C,SAAS,KAAe,OAAO,OAAgB,CAAA,CAAC,CAAC;KAClD,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-plus",
3
- "version": "4.6.3",
3
+ "version": "4.8.1",
4
4
  "description": "Provides additional types for TypeScript.",
5
5
  "homepage": "https://github.com/unional/type-plus",
6
6
  "bugs": {
@@ -35,6 +35,24 @@ test('can default with null', () => {
35
35
  isType.equal<true, number | null, typeof a>()
36
36
  })
37
37
 
38
+ test('remove optional/undefined when default is provided', () => {
39
+ interface S {
40
+ variant?: 'abc' | 'def'
41
+ }
42
+ const s: S = {}
43
+ const [a] = split(s, { variant: 'def' })
44
+ isType.equal<true, 'abc' | 'def', typeof a.variant>()
45
+ })
46
+
47
+ test('keep undefined when default is undefined', () => {
48
+ interface S {
49
+ variant?: 'abc' | 'def'
50
+ }
51
+ const s: S = {}
52
+ const [a] = split(s, { variant: undefined })
53
+ isType.equal<true, 'abc' | 'def' | undefined, typeof a.variant>()
54
+ })
55
+
38
56
 
39
57
  test('can default with false', () => {
40
58
  const s: { a?: number | boolean } = {}
@@ -4,7 +4,7 @@ import { reduceByKey } from './reduceKey'
4
4
 
5
5
  type Splitter<T extends AnyRecord> = Partial<{ [k in keyof T]: T[k] | undefined }>
6
6
  export type Split<T extends AnyRecord, S extends AnyRecord> = {
7
- [k in keyof S]: S[k] extends undefined ? T[k] : NonNullable<T[k]> | S[k]
7
+ [k in keyof S]-?: S[k] extends undefined ? T[k] : NonNullable<T[k]> | S[k]
8
8
  }
9
9
 
10
10
  /**
@@ -1,38 +1,58 @@
1
1
  import { isType, stub } from '..'
2
2
 
3
- test('stub is a partial of the actual object', () => {
4
- const real = { a: 1, b: { c: 2 }, d: 3 }
3
+ describe('stub()', () => {
4
+ test('stub is a partial of the actual object', () => {
5
+ const real = { a: 1, b: { c: 2 }, d: 3 }
5
6
 
6
- const a = stub<typeof real>({ a: 2 })
7
- expect(a.a).toBe(2)
8
- isType.equal<true, typeof a, typeof real>()
9
- })
7
+ const a = stub<typeof real>({ a: 2 })
8
+ expect(a.a).toBe(2)
9
+ isType.equal<true, typeof a, typeof real>()
10
+ })
11
+
12
+ test('stub function retains param types', () => {
13
+ function real(a: string, b: number): boolean { return a === String(b) }
10
14
 
11
- test('stub function retains param types', () => {
12
- function real(a: string, b: number): boolean { return a === String(b) }
15
+ const a = stub<typeof real>((_a, _b) => {
16
+ isType.equal<true, string, typeof _a>()
17
+ isType.equal<true, number, typeof _b>()
18
+ return false
19
+ })
13
20
 
14
- const a = stub<typeof real>((_a, _b) => {
15
- isType.equal<true, string, typeof _a>()
16
- isType.equal<true, number, typeof _b>()
17
- return false
21
+ expect(a('1', 1)).toBe(false)
22
+ isType.equal<true, typeof a, typeof real>()
18
23
  })
19
24
 
20
- expect(a('1', 1)).toBe(false)
21
- isType.equal<true, typeof a, typeof real>()
22
- })
25
+ test('stub function params can be omitted', () => {
26
+ function real(a: string, b: number): boolean { return a === String(b) }
23
27
 
24
- test('stub function params can be omitted', () => {
25
- function real(a: string, b: number): boolean { return a === String(b) }
28
+ const a = stub<typeof real>(() => false)
26
29
 
27
- const a = stub<typeof real>(() => false)
30
+ expect(a('1', 1)).toBe(false)
31
+ isType.equal<true, typeof a, typeof real>()
32
+ })
28
33
 
29
- expect(a('1', 1)).toBe(false)
30
- isType.equal<true, typeof a, typeof real>()
34
+ test('stub input can be omitted', () => {
35
+ const real = { a: 1, b: { c: 2 }, d: 3 }
36
+
37
+ const a = stub<typeof real>()
38
+ isType.equal<true, typeof a, typeof real>()
39
+ })
31
40
  })
32
41
 
33
- test('stub input can be omitted', () => {
34
- const real = { a: 1, b: { c: 2 }, d: 3 }
42
+ describe('stub.build()', () => {
43
+ test('build a stub function', () => {
44
+ const real = { a: 1, b: { c: 2 }, d: 3 }
35
45
 
36
- const a = stub<typeof real>()
37
- isType.equal<true, typeof a, typeof real>()
46
+ const s = stub.build<typeof real>()
47
+ const a = s({ a: 2 })
48
+ expect(a.a).toBe(2)
49
+ isType.equal<true, typeof a, typeof real>()
50
+ })
51
+ test('can define init value', () => {
52
+ type S = { a: number, b: string }
53
+ const s = stub.build<S>({ b: 'b' })
54
+ const a = s({ a: 1 })
55
+ expect(a).toEqual({ a: 1, b: 'b' })
56
+ isType.equal<true, S, typeof a>()
57
+ })
38
58
  })
@@ -1,3 +1,4 @@
1
+ import { requiredDeep } from 'unpartial'
1
2
  import { AnyFunction } from '../function'
2
3
  import { RecursivePartial } from '../object'
3
4
 
@@ -8,3 +9,14 @@ export namespace stub {
8
9
  export function stub<T>(stub?: stub.Param<T>) {
9
10
  return stub as T
10
11
  }
12
+
13
+ /**
14
+ * builds a stub function
15
+ */
16
+ stub.build = function build<T>(init?: stub.Param<T>) {
17
+ return function (value?: stub.Param<T>) {
18
+ return init
19
+ ? stub<T>(requiredDeep(init as any, value as any) as any)
20
+ : stub<T>(value)
21
+ }
22
+ }
@@ -1,4 +1,4 @@
1
- import { as, asAny, isType } from '..'
1
+ import { amend, as, asAny, isType } from '..'
2
2
 
3
3
  describe('as<T>()', () => {
4
4
  test('defaults subject type to unknown', () => {
@@ -31,3 +31,15 @@ describe('asAny()', () => {
31
31
  })
32
32
  })
33
33
 
34
+ describe('amend<T>()', () => {
35
+ test('assert subject as (subject & T)', () => {
36
+ const s = { a: 1 }
37
+ const a = amend(s).union<{ b: string }>()
38
+ isType.equal<true, { a: number } & { b: string }, typeof a>()
39
+ })
40
+ test('assert subject as (subject | T)', () => {
41
+ const s = { a: 1 }
42
+ const a = amend(s).intersect<{ b: string }>()
43
+ isType.equal<true, { a: number } | { b: string }, typeof a>()
44
+ })
45
+ })
package/ts/utils/as.ts CHANGED
@@ -5,3 +5,13 @@ export function as<T>(subject: unknown): T {
5
5
  export function asAny(subject: unknown): any {
6
6
  return subject
7
7
  }
8
+
9
+ /**
10
+ * amend `subject` with type `T`
11
+ */
12
+ export function amend<S>(subject: S) {
13
+ return {
14
+ union<T>(): T & S { return subject as T & S },
15
+ intersect<T>(): T | S { return subject as T | S }
16
+ }
17
+ }