inferred-types 0.35.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +2 -34
  2. package/dist/index.d.ts +1803 -1663
  3. package/dist/index.mjs +95 -26
  4. package/package.json +12 -11
  5. package/src/runtime/combinators/filter.ts +0 -1
  6. package/src/runtime/lists/asArray.ts +8 -4
  7. package/src/runtime/lists/createConverter.ts +62 -0
  8. package/src/runtime/lists/index.ts +1 -0
  9. package/src/runtime/literals/box.ts +41 -20
  10. package/src/runtime/literals/ensureLeading.ts +17 -0
  11. package/src/runtime/literals/ensureTrailing.ts +17 -0
  12. package/src/runtime/literals/index.ts +4 -2
  13. package/src/runtime/literals/pathJoin.ts +22 -7
  14. package/src/runtime/literals/{stripStarting.ts → stripLeading.ts} +4 -4
  15. package/src/runtime/literals/stripTrailing.ts +15 -0
  16. package/src/runtime/literals/wide.ts +13 -0
  17. package/src/runtime/type-checks/ifSameType.ts +20 -0
  18. package/src/runtime/type-checks/index.ts +1 -0
  19. package/src/runtime/type-checks/isBoolean.ts +2 -1
  20. package/src/runtime/type-checks/isFunction.ts +2 -4
  21. package/src/runtime/type-checks/isObject.ts +10 -2
  22. package/src/runtime/type-checks/isString.ts +1 -1
  23. package/src/runtime/type-checks/isUndefined.ts +8 -0
  24. package/src/types/alphabetic/EnsureLeading.ts +24 -0
  25. package/src/types/alphabetic/EnsureTrailing.ts +24 -0
  26. package/src/types/alphabetic/PathJoin.ts +43 -31
  27. package/src/types/alphabetic/{StripStarting.ts → StripLeading.ts} +1 -1
  28. package/src/types/alphabetic/{StripEnding.ts → StripTrailing.ts} +1 -1
  29. package/src/types/alphabetic/index.ts +4 -2
  30. package/src/types/boolean-logic/HasParameters.ts +21 -0
  31. package/src/types/boolean-logic/array.ts +2 -2
  32. package/src/types/boolean-logic/boolean.ts +1 -1
  33. package/src/types/boolean-logic/equivalency.ts +2 -2
  34. package/src/types/boolean-logic/index.ts +1 -0
  35. package/src/types/dictionary/props.ts +5 -0
  36. package/src/types/lists/ConvertAndMap.ts +151 -0
  37. package/src/types/type-conversion/Widen.ts +15 -0
  38. package/tests/boolean-logic/HasParameters.ts +29 -0
  39. package/tests/lists/asArray.test.ts +19 -1
  40. package/tests/literals/EnsureStripLeadingTrailing.test.ts +79 -0
  41. package/tests/literals/PathJoin.test.ts +44 -37
  42. package/tests/literals/box.test.ts +31 -23
  43. package/tests/runtime/if-is.spec.ts +66 -5
  44. package/tests/runtime/map-and-convert.test.ts +31 -0
  45. package/dist/index.js +0 -868
  46. package/src/runtime/literals/stripEnding.ts +0 -9
@@ -13,6 +13,8 @@ describe("PathJoin<T,U>", () => {
13
13
  type T2 = PathJoin<"foo/", "bar">;
14
14
  type T3 = PathJoin<"foo", "/bar">;
15
15
  type T4 = PathJoin<"foo/", "/bar">;
16
+ type T5 = PathJoin<"/foo/", "/bar">;
17
+ type T6 = PathJoin<"foo/", "/bar/">;
16
18
 
17
19
  type cases = [
18
20
  // neither have divider
@@ -21,9 +23,27 @@ describe("PathJoin<T,U>", () => {
21
23
  Expect<Equal<T2, "foo/bar">>,
22
24
  Expect<Equal<T3, "foo/bar">>,
23
25
  // both have
24
- Expect<Equal<T4, "foo/bar">>
26
+ Expect<Equal<T4, "foo/bar">>,
27
+ // leading slash
28
+ Expect<Equal<T5, "/foo/bar">>,
29
+ // trailing slash
30
+ Expect<Equal<T6, "foo/bar/">>
25
31
  ];
26
- const cases: cases = [true, true, true, true];
32
+ const cases: cases = [true, true, true, true, true, true];
33
+ });
34
+
35
+ it("PathJoin<T,U> with U as array", () => {
36
+ type T1 = PathJoin<"foo", ["bar", "baz"]>;
37
+ type T2 = PathJoin<"/foo/", ["/bar/", "/baz/"]>;
38
+ type T3 = PathJoin<"/foo/", ["bar", "/baz"]>;
39
+
40
+ type cases = [
41
+ //
42
+ Expect<Equal<T1, "foo/bar/baz">>,
43
+ Expect<Equal<T2, "/foo/bar/baz/">>,
44
+ Expect<Equal<T3, "/foo/bar/baz">>
45
+ ];
46
+ const cases: cases = [true, true, true];
27
47
  });
28
48
 
29
49
  it("wide types mixed in", () => {
@@ -43,45 +63,32 @@ describe("PathJoin<T,U>", () => {
43
63
  });
44
64
 
45
65
  describe("pathJoin() runtime util", () => {
46
- it("happy path", () => {
47
- const t1 = pathJoin("foo", "bar" as string);
48
- const t2 = pathJoin("foo/", "bar" as string);
49
- const t3 = pathJoin("foo" as string, "/bar");
50
- const t4 = pathJoin("foo/" as string, "/bar");
51
- const t5 = pathJoin("foo/" as string, "bar");
52
-
53
- // runtime tests
54
- [t1, t2, t3, t4].forEach((test) => expect(test).toBe("foo/bar"));
55
-
56
- // type tests
57
- type cases = [
58
- Expect<Equal<typeof t1, `foo/${string}`>>,
59
- Expect<Equal<typeof t2, `foo/${string}`>>,
60
- Expect<Equal<typeof t3, `${string}/bar`>>,
61
- Expect<Equal<typeof t4, `${string}/bar`>>,
62
- Expect<Equal<typeof t5, `${string}bar`>>
63
- ];
64
- const cases: cases = [true, true, true, true, true];
65
- });
66
-
67
- it("with wide types", () => {
66
+ it("no leading or trailing slashes", () => {
68
67
  const t1 = pathJoin("foo", "bar");
69
68
  const t2 = pathJoin("foo/", "bar");
70
69
  const t3 = pathJoin("foo", "/bar");
71
70
  const t4 = pathJoin("foo/", "/bar");
72
- // runtime tests
73
- [t1, t2, t3, t4].forEach((test) => expect(test, "runtime failure").toBe("foo/bar"));
71
+ // multi
72
+ const t5 = pathJoin("foo/", "bar", "/baz");
73
+ const t6 = pathJoin("foo/", "bar/", "/baz");
74
74
 
75
- // type tests
76
- type cases = [
77
- // neither have divider
78
- Expect<Equal<typeof t1, "foo/bar">>,
79
- // one has, one does not
80
- Expect<Equal<typeof t2, "foo/bar">>,
81
- Expect<Equal<typeof t3, "foo/bar">>,
82
- // both have
83
- Expect<Equal<typeof t4, "foo/bar">>
84
- ];
85
- const cases: cases = [true, true, true, true];
75
+ [t1, t2, t3, t4].forEach((test) =>
76
+ expect(test, "no leading or trailing slash").toBe("foo/bar")
77
+ );
78
+ [t5, t6].forEach((test) =>
79
+ expect(test, "no leading or trailing slash (with multi U)").toBe("foo/bar/baz")
80
+ );
81
+ });
82
+
83
+ it("leading and trailing slashes", () => {
84
+ const t1 = pathJoin("/foo", "bar");
85
+ const t2 = pathJoin("foo/", "bar/");
86
+ const t3 = pathJoin("/foo", "bar", "/baz");
87
+ const t4 = pathJoin("foo/", "/bar/", "/baz/");
88
+ // runtime tests
89
+ expect(t1).toBe("/foo/bar");
90
+ expect(t2).toBe("foo/bar/");
91
+ expect(t3).toBe("/foo/bar/baz");
92
+ expect(t4).toBe("foo/bar/baz/");
86
93
  });
87
94
  });
@@ -1,29 +1,23 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
  import { Equal, Expect } from "@type-challenges/utils";
3
- import { Box, box, BoxedFnParams, BoxValue } from "src/runtime";
3
+ import { Box, box, BoxedFnParams, BoxValue, unbox } from "src/runtime";
4
4
  import { First } from "src/types/lists/First";
5
5
 
6
6
  // [Instantiation Expressions](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7-beta/#instantiation-expressions)
7
7
 
8
- describe("boxing / unboxing", () => {
9
- // it("NarrowBox<B,N> utility", () => {
10
- // const fn = <T extends string>(i: T) => `Hello ${i}` as const;
11
- // const b = box(fn);
12
- // const b2 = b.narrow<["foo" | "bar"]>();
13
- // const b3 = b2("foo");
14
-
15
- // type B = typeof b;
16
- // });
8
+ // this exercise was started around the time that Instantiation expressions
9
+ // were first introduced and with the hope that this would help narrow functions
10
+ // which have an inner generic that provides narrow typing.
17
11
 
12
+ describe("boxing / unboxing", () => {
18
13
  it("box a function with generic", () => {
19
14
  const fn = <T extends string>(i: T) => `Hello ${i}` as const;
20
15
  const b = box(fn);
21
- const ub = b.unbox();
22
- type UB = typeof ub;
23
- const unboxedFn = b.unbox()("foo");
24
- const unboxedFn2 = b.unbox()("foo" as string);
25
- type UBF = typeof unboxedFn;
26
- type UBF2 = typeof unboxedFn2;
16
+ const globalUnbox = unbox(b);
17
+ type UB = typeof globalUnbox;
18
+ const usingValue = b.value("foo");
19
+ const unboxedNarrow = b.unbox("foo");
20
+ const unboxedWide = b.unbox("foo" as string);
27
21
 
28
22
  const bn = box(42);
29
23
  type BN = typeof bn;
@@ -39,8 +33,13 @@ describe("boxing / unboxing", () => {
39
33
 
40
34
  // runtime
41
35
  expect(typeof b).toBe("object");
42
- expect(typeof ub).toBe("function");
43
- expect(unboxedFn).toBe("Hello foo");
36
+ expect(
37
+ typeof globalUnbox,
38
+ `using unbox(fn) should have returned function: ${globalUnbox}`
39
+ ).toBe("function");
40
+ expect(usingValue).toBe("Hello foo");
41
+ expect(unboxedNarrow).toBe("Hello foo");
42
+ expect(unboxedWide).toBe("Hello foo");
44
43
 
45
44
  expect(rn).toBe(42);
46
45
  expect(rn2).toBe(42);
@@ -57,10 +56,19 @@ describe("boxing / unboxing", () => {
57
56
  Expect<Equal<BF, string>>,
58
57
  /** unboxing fn results in same fn including generics */
59
58
  Expect<Equal<UB, typeof fn>>,
60
- /** generic for fn provides strong literal type after unboxing */
61
- Expect<Equal<UBF, "Hello foo">>,
62
- /** generic still provides some strong typing when a wide type is passed in */
63
- Expect<Equal<UBF2, `Hello ${string}`>>,
59
+ /** this uses the VALUE prop and provides the TARGET resolution for unbox */
60
+ Expect<Equal<typeof usingValue, "Hello foo">>,
61
+ /**
62
+ * using the passthrough feature of `b.unbox(val)` we would ideally like to
63
+ * get same narrow type as test above but it is reduced to an "ok" level for
64
+ * now
65
+ */
66
+ Expect<Equal<typeof unboxedNarrow, `Hello ${string}`>>,
67
+ /**
68
+ * Note, however, that the wide value of string passed in resolves in the same
69
+ * manner which helps to point to where resolution is being lost
70
+ */
71
+ Expect<Equal<typeof unboxedWide, `Hello ${string}`>>,
64
72
 
65
73
  // NUMBER BOXes
66
74
  Expect<Equal<BN, Box<42>>>,
@@ -72,6 +80,6 @@ describe("boxing / unboxing", () => {
72
80
  // HYBRID
73
81
  Expect<Equal<HV, Hybrid>>
74
82
  ];
75
- const cases: cases = [true, true, true, true, true, true, true, true, true, true];
83
+ const cases: cases = [true, true, true, true, true, true, true, true, true, true, true];
76
84
  });
77
85
  });
@@ -6,6 +6,7 @@ import {
6
6
  ifArrayPartial,
7
7
  ifBoolean,
8
8
  ifNumber,
9
+ ifSameType,
9
10
  ifString,
10
11
  ifTrue,
11
12
  ifUndefined,
@@ -13,13 +14,13 @@ import {
13
14
  } from "src/runtime/type-checks";
14
15
  import { EndsWith, Extends, LowerAlpha, Or, StartsWith } from "src/types";
15
16
  import { ifStartsWith, startsWith } from "src/runtime/type-checks/startsWith";
16
- import { box } from "src/runtime/literals";
17
+ import { box, wide } from "src/runtime/literals";
17
18
  import { or } from "src/runtime";
18
19
 
19
20
  describe("runtime if/is", () => {
20
21
  it("ifString(v,i,e)", () => {
21
- const t = ifString("foo", 42, false);
22
- const f = ifString(-1, "yikes", 42);
22
+ const t = ifString("foo", () => 42, false);
23
+ const f = ifString(-1, () => "yikes", 42);
23
24
 
24
25
  type cases = [
25
26
  Expect<Equal<typeof t, 42>>, //
@@ -67,10 +68,10 @@ describe("runtime if/is", () => {
67
68
  const f1 = box(<T extends string>(input: T) => `Hello ${input}` as const);
68
69
  const f2 = box(<T extends string>(input: T) => `Get out ${input}!` as const);
69
70
  const t = <T extends string, B extends boolean>(i: T, nice: B) => {
70
- return isTrue(nice) ? f1.unbox()(i) : f2.unbox()(i);
71
+ return isTrue(nice) ? f1.value(i) : f2.value(i);
71
72
  };
72
73
  const t2 = <T extends string, B extends boolean>(i: T, nice: B) =>
73
- ifTrue(nice, f1.unbox()(i), f2.unbox()(i));
74
+ ifTrue(nice, f1.value(i), f2.value(i));
74
75
 
75
76
  // both approaches produce correct result
76
77
  const r1 = t("Joe", true);
@@ -326,4 +327,64 @@ describe("runtime if/is", () => {
326
327
  ];
327
328
  const cases: cases = [true, true, true];
328
329
  });
330
+
331
+ it("ifSameType", () => {
332
+ const t1 = ifSameType(
333
+ "foo",
334
+ wide.string,
335
+ (i) => `Hello ${i}`,
336
+ (i) => `Goodbye ${i}`
337
+ );
338
+ const t2 = ifSameType(
339
+ 42,
340
+ wide.string,
341
+ (i) => `Hello ${i}`,
342
+ (i) => `Goodbye ${i}`
343
+ );
344
+ const t3 = ifSameType(
345
+ "foo" as string,
346
+ wide.string,
347
+ (i) => `Hello ${i}`,
348
+ (i) => `Goodbye ${i}`
349
+ );
350
+ const t4 = ifSameType(
351
+ 42 as number,
352
+ wide.string,
353
+ (i) => `Hello ${i}`,
354
+ (i) => `Goodbye ${i}`
355
+ );
356
+
357
+ const nested = ifSameType(
358
+ false,
359
+ wide.string,
360
+ (i) => `Hello ${i}`,
361
+ (i) =>
362
+ ifSameType(
363
+ i,
364
+ wide.number,
365
+ (n) => n,
366
+ (i) =>
367
+ ifSameType(
368
+ i,
369
+ wide.boolean,
370
+ (b) => `I'm a boolean value of ${b}`,
371
+ () => ""
372
+ )
373
+ )
374
+ );
375
+
376
+ type cases = [
377
+ // matches (narrow)
378
+ Expect<Equal<typeof t1, "Hello foo">>,
379
+ // does not match (narrow)
380
+ Expect<Equal<typeof t2, `Goodbye 42`>>,
381
+ // matches (wide)
382
+ Expect<Equal<typeof t3, `Hello ${string}`>>,
383
+ // does not match (wide)
384
+ Expect<Equal<typeof t4, `Goodbye ${number}`>>,
385
+ // nested
386
+ Expect<Equal<typeof nested, `I'm a boolean value of false`>>
387
+ ];
388
+ const cases: cases = [true, true, true, true, true];
389
+ });
329
390
  });
@@ -0,0 +1,31 @@
1
+ import { Equal, Expect } from "@type-challenges/utils";
2
+ import { createConverter } from "src/runtime/lists/createConverter";
3
+ import { describe, it, expect } from "vitest";
4
+
5
+ // Note: while type tests fail visible inspection they pass from Vitest
6
+ // standpoint so always be sure to run `tsc --noEmit` over your test files to
7
+ // gain validation that no new type vulnerabilities have cropped up.
8
+
9
+ describe("createConverter()", () => {
10
+ it("basic converter setup", () => {
11
+ const convert = createConverter({
12
+ string: (s) => `Hello ${s}`,
13
+ number: (n) => `The number was ${n}`,
14
+ object: (o) => `An object with keys ${Object.keys(o).join(", ")}`,
15
+ });
16
+
17
+ const t1 = convert("foo");
18
+ const t2 = convert(42);
19
+ const t3 = convert({ foo: 42, bar: 12 });
20
+ expect(t1).toBe("Hello foo");
21
+ expect(t2).toBe("The number was 42");
22
+
23
+ type cases = [
24
+ // TODO: get the final narrowness resolved ... this should be doable
25
+ Expect<Equal<typeof t1, `Hello ${string}`>>,
26
+ Expect<Equal<typeof t2, `The number was ${number}`>>,
27
+ Expect<Equal<typeof t3, `An object with keys ${string}`>>
28
+ ];
29
+ const cases: cases = [true, true, true];
30
+ });
31
+ });