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.
- package/README.md +2 -34
- package/dist/index.d.ts +1803 -1663
- package/dist/index.mjs +95 -26
- package/package.json +12 -11
- package/src/runtime/combinators/filter.ts +0 -1
- package/src/runtime/lists/asArray.ts +8 -4
- package/src/runtime/lists/createConverter.ts +62 -0
- package/src/runtime/lists/index.ts +1 -0
- package/src/runtime/literals/box.ts +41 -20
- package/src/runtime/literals/ensureLeading.ts +17 -0
- package/src/runtime/literals/ensureTrailing.ts +17 -0
- package/src/runtime/literals/index.ts +4 -2
- package/src/runtime/literals/pathJoin.ts +22 -7
- package/src/runtime/literals/{stripStarting.ts → stripLeading.ts} +4 -4
- package/src/runtime/literals/stripTrailing.ts +15 -0
- package/src/runtime/literals/wide.ts +13 -0
- package/src/runtime/type-checks/ifSameType.ts +20 -0
- package/src/runtime/type-checks/index.ts +1 -0
- package/src/runtime/type-checks/isBoolean.ts +2 -1
- package/src/runtime/type-checks/isFunction.ts +2 -4
- package/src/runtime/type-checks/isObject.ts +10 -2
- package/src/runtime/type-checks/isString.ts +1 -1
- package/src/runtime/type-checks/isUndefined.ts +8 -0
- package/src/types/alphabetic/EnsureLeading.ts +24 -0
- package/src/types/alphabetic/EnsureTrailing.ts +24 -0
- package/src/types/alphabetic/PathJoin.ts +43 -31
- package/src/types/alphabetic/{StripStarting.ts → StripLeading.ts} +1 -1
- package/src/types/alphabetic/{StripEnding.ts → StripTrailing.ts} +1 -1
- package/src/types/alphabetic/index.ts +4 -2
- package/src/types/boolean-logic/HasParameters.ts +21 -0
- package/src/types/boolean-logic/array.ts +2 -2
- package/src/types/boolean-logic/boolean.ts +1 -1
- package/src/types/boolean-logic/equivalency.ts +2 -2
- package/src/types/boolean-logic/index.ts +1 -0
- package/src/types/dictionary/props.ts +5 -0
- package/src/types/lists/ConvertAndMap.ts +151 -0
- package/src/types/type-conversion/Widen.ts +15 -0
- package/tests/boolean-logic/HasParameters.ts +29 -0
- package/tests/lists/asArray.test.ts +19 -1
- package/tests/literals/EnsureStripLeadingTrailing.test.ts +79 -0
- package/tests/literals/PathJoin.test.ts +44 -37
- package/tests/literals/box.test.ts +31 -23
- package/tests/runtime/if-is.spec.ts +66 -5
- package/tests/runtime/map-and-convert.test.ts +31 -0
- package/dist/index.js +0 -868
- 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("
|
|
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
|
-
//
|
|
73
|
-
|
|
71
|
+
// multi
|
|
72
|
+
const t5 = pathJoin("foo/", "bar", "/baz");
|
|
73
|
+
const t6 = pathJoin("foo/", "bar/", "/baz");
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
22
|
-
type UB = typeof
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
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(
|
|
43
|
-
|
|
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
|
-
/**
|
|
61
|
-
Expect<Equal<
|
|
62
|
-
/**
|
|
63
|
-
|
|
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.
|
|
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.
|
|
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
|
+
});
|