inferred-types 0.33.4 → 0.34.2

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 (48) hide show
  1. package/.vscode/settings.json +1 -0
  2. package/dist/index.d.ts +204 -103
  3. package/dist/index.js +20 -6
  4. package/dist/index.mjs +17 -6
  5. package/package.json +3 -3
  6. package/src/runtime/combinators/or.ts +4 -14
  7. package/src/runtime/type-checks/isArray.ts +30 -1
  8. package/src/runtime/type-checks/isBoolean.ts +1 -1
  9. package/src/runtime/type-checks/isFalse.ts +24 -12
  10. package/src/runtime/type-checks/isObject.ts +1 -1
  11. package/src/runtime/type-checks/isString.ts +1 -1
  12. package/src/runtime/type-checks/isTrue.ts +13 -29
  13. package/src/runtime/type-checks/isUndefined.ts +1 -1
  14. package/src/runtime/type-checks/startsWith.ts +9 -11
  15. package/src/types/Mutable.ts +1 -1
  16. package/src/types/Narrowable.ts +1 -2
  17. package/src/types/boolean-logic/EndsWith.ts +40 -0
  18. package/src/types/boolean-logic/Extends.ts +22 -0
  19. package/src/types/{type-checks → boolean-logic}/Includes.ts +3 -4
  20. package/src/types/{type-checks → boolean-logic}/IsLiteral.ts +52 -5
  21. package/src/types/boolean-logic/IsScalar.ts +20 -0
  22. package/src/types/{type-checks → boolean-logic}/IsUndefined.ts +5 -1
  23. package/src/types/boolean-logic/Or.ts +12 -0
  24. package/src/types/{type-checks → boolean-logic}/StartsWith.ts +12 -13
  25. package/src/types/{type-checks → boolean-logic}/TypeDefault.ts +1 -1
  26. package/src/types/boolean-logic/array.ts +57 -0
  27. package/src/types/boolean-logic/boolean.ts +84 -0
  28. package/src/types/boolean-logic/equivalency.ts +15 -0
  29. package/src/types/{type-checks → boolean-logic}/index.ts +4 -3
  30. package/src/types/{type-checks → boolean-logic}/object.ts +4 -1
  31. package/src/types/{type-checks → boolean-logic}/string.ts +1 -1
  32. package/src/types/dictionary/MapTo.ts +1 -1
  33. package/src/types/functions/LogicFunction.ts +1 -1
  34. package/src/types/index.ts +1 -1
  35. package/src/types/lists/FilterTuple.ts +20 -0
  36. package/src/types/lists/index.ts +1 -0
  37. package/tests/boolean-logic/Contains.test.ts +55 -0
  38. package/tests/{TypeInfo → boolean-logic}/IsLiteral.spec.ts +0 -0
  39. package/tests/dictionary/{PrependValuesWithFunction.ts → PrependValuesWithFunction.test.ts} +0 -0
  40. package/tests/dictionary/TypeDefault.test.ts +1 -1
  41. package/tests/lists/Length.test.ts +19 -0
  42. package/tests/runtime/if-is.spec.ts +113 -5
  43. package/src/types/type-checks/EndsWith.ts +0 -22
  44. package/src/types/type-checks/Extends.ts +0 -14
  45. package/src/types/type-checks/IsBooleanLiteral.ts +0 -16
  46. package/src/types/type-checks/IsNumericLiteral.ts +0 -16
  47. package/src/types/type-checks/IsScalar.ts +0 -14
  48. package/src/types/type-checks/IsStringLiteral.ts +0 -14
@@ -1,8 +1,7 @@
1
+ export * from "./array";
1
2
  export * from "./Includes";
2
- export * from "./IsBooleanLiteral";
3
- export * from "./IsNumericLiteral";
3
+ export * from "./boolean";
4
4
  export * from "./IsScalar";
5
- export * from "./IsStringLiteral";
6
5
  export * from "./IsLiteral";
7
6
  export * from "./IsUndefined";
8
7
  export * from "./Extends";
@@ -10,3 +9,5 @@ export * from "./TypeDefault";
10
9
  export * from "./object";
11
10
  export * from "./StartsWith";
12
11
  export * from "./EndsWith";
12
+ export * from "./Or";
13
+ export * from "./equivalency";
@@ -1,5 +1,6 @@
1
1
  import { FunctionType } from "../FunctionType";
2
2
  import { Mutable } from "../Mutable";
3
+ import { Narrowable } from "../Narrowable";
3
4
 
4
5
  /**
5
6
  * **IsObject**
@@ -24,4 +25,6 @@ export type IsObject<T> = Mutable<T> extends Record<string, any>
24
25
  * Branch type utility with return `IF` when `T` extends an object type
25
26
  * and `ELSE` otherwise
26
27
  */
27
- export type IfObject<T, IF, ELSE> = IsObject<T> extends true ? IF : ELSE;
28
+ export type IfObject<T, IF extends Narrowable, ELSE extends Narrowable> = IsObject<T> extends true
29
+ ? IF
30
+ : ELSE;
@@ -18,4 +18,4 @@ export type IfString<
18
18
  T extends Narrowable, //
19
19
  IF extends Narrowable,
20
20
  ELSE extends Narrowable
21
- > = IsString<T> extends true ? IF : ELSE;
21
+ > = IsString<T> extends true ? IF : IsString<T> extends false ? ELSE : IF | ELSE;
@@ -6,7 +6,7 @@ import {
6
6
  DefaultOneToOneMapping,
7
7
  } from "src/runtime/dictionary/mapTo";
8
8
  import { EnumValues } from "../EnumValues";
9
- import { TypeDefault } from "../type-checks/TypeDefault";
9
+ import { TypeDefault } from "../boolean-logic/TypeDefault";
10
10
 
11
11
  /**
12
12
  * Expresses relationship between inputs/outputs:
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * A function which returns a boolean value
3
3
  */
4
- export type LogicFunction<T extends any[]> = (...args: T) => boolean;
4
+ export type LogicFunction<T extends readonly any[]> = (...args: T) => boolean;
@@ -41,7 +41,7 @@ export * from "./literal-unions/index";
41
41
  export * from "./string-literals/index";
42
42
  export * from "./tuples/index";
43
43
  export * from "./type-conversion/index";
44
- export * from "./type-checks/index";
44
+ export * from "./boolean-logic/index";
45
45
 
46
46
  // #endregion auto-indexed files
47
47
 
@@ -0,0 +1,20 @@
1
+ /**
2
+ * **FilterTuple**
3
+ *
4
+ * Allows a known tuple `T` to be _filtered down_ by eliminating all items
5
+ * in the Tuple that _extend_ type `F`
6
+ * ```ts
7
+ * type T = [1,"foo",3];
8
+ * // [1,3]
9
+ * type T2 = FilterTuple<T, string>;
10
+ * ```
11
+ */
12
+ export type FilterTuple<
13
+ TTuple extends any[] | readonly any[],
14
+ TFilter,
15
+ Result extends any[] = []
16
+ > = TTuple extends [infer A, ...infer R]
17
+ ? [A] extends [TFilter]
18
+ ? FilterTuple<R, TFilter, Result>
19
+ : FilterTuple<R, TFilter, [...Result, A]>
20
+ : Result;
@@ -8,6 +8,7 @@
8
8
  export * from "./AfterFirst";
9
9
  export * from "./First";
10
10
  export * from "./FirstString";
11
+ export * from "./FilterTuple";
11
12
  export * from "./Split";
12
13
  export * from "./UniqueForProp";
13
14
 
@@ -0,0 +1,55 @@
1
+ import { Equal, Expect } from "@type-challenges/utils";
2
+ import { Contains, NarrowlyContains } from "src/types/boolean-logic/array";
3
+ import { describe, it } from "vitest";
4
+
5
+ describe("Contains<T,A>", () => {
6
+ it("happy-path", () => {
7
+ type T1 = [number, 32, 64, "foo"];
8
+ type T2 = [false, true];
9
+ type T3 = [42, 64, 128];
10
+ type T4 = ["foo", "bar"];
11
+
12
+ type cases = [
13
+ // "foo" extends string so true
14
+ Expect<Equal<Contains<string, T1>, true>>,
15
+ // "bar" does NOT extend "foo"
16
+ Expect<Equal<Contains<"bar", T1>, false>>,
17
+ // T4 has literal string but this will match the wide type string
18
+ Expect<Equal<Contains<string, T4>, true>>,
19
+ // T1 has both wide and narrow versions of "number"
20
+ Expect<Equal<Contains<number, T1>, true>>,
21
+ // T3 has narrow versions of "number"
22
+ Expect<Equal<Contains<number, T3>, true>>,
23
+ // boolean literals evaluate to wide type
24
+ Expect<Equal<Contains<boolean, T2>, true>>
25
+ ];
26
+ const cases: cases = [true, true, true, true, true, true];
27
+ });
28
+ });
29
+
30
+ describe("NarrowlyContains<T,A>", () => {
31
+ it("happy-path", () => {
32
+ type T1 = [number, 32, 64, "foo"];
33
+ type T2 = [false, true];
34
+ type T3 = [42, 64, 128];
35
+ type T4 = ["foo", "bar"];
36
+
37
+ type cases = [
38
+ // "foo" is not equal to string
39
+ Expect<Equal<NarrowlyContains<string, T1>, false>>,
40
+ // "foo" does equal "foo"
41
+ Expect<Equal<NarrowlyContains<"foo", T1>, true>>,
42
+ // T4 has literal string but this doesn't match with NarrowlyContains
43
+ Expect<Equal<NarrowlyContains<string, T4>, false>>,
44
+ // T1 has both wide and narrow versions of "number" but match is only on wide type
45
+ Expect<Equal<NarrowlyContains<number, T1>, true>>,
46
+ // T3 has matches on narrow number
47
+ Expect<Equal<NarrowlyContains<42, T3>, true>>,
48
+ // T3 identifies a non-match of narrow numbers
49
+ Expect<Equal<NarrowlyContains<442, T3>, false>>,
50
+ // boolean literals evaluate to wide type
51
+ Expect<Equal<NarrowlyContains<boolean, T2>, false>>
52
+ ];
53
+ const cases: cases = [true, true, true, true, true, true, true];
54
+ });
55
+ });
@@ -1,6 +1,6 @@
1
1
  import { describe, it } from "vitest";
2
2
  import { Equal, Expect } from "@type-challenges/utils";
3
- import { TypeDefault } from "src/types/type-checks/TypeDefault";
3
+ import { TypeDefault } from "src/types/boolean-logic/TypeDefault";
4
4
  import { literal } from "src/runtime/literals";
5
5
 
6
6
  describe("TypeDefault<T,D>", () => {
@@ -0,0 +1,19 @@
1
+ import { Equal, Expect } from "@type-challenges/utils";
2
+ import { Length } from "src/types";
3
+ import { describe, it } from "vitest";
4
+
5
+ describe("Length<T>", () => {
6
+ it("happy-path", () => {
7
+ const a1 = [1, 2, 3] as const;
8
+ const a2 = [1, 2, 3, 4, 5, 6] as const;
9
+ type A1 = typeof a1;
10
+ type A2 = typeof a2;
11
+
12
+ type cases = [
13
+ //
14
+ Expect<Equal<Length<A1>, 3>>,
15
+ Expect<Equal<Length<A2>, 6>>
16
+ ];
17
+ const cases: cases = [true, true];
18
+ });
19
+ });
@@ -2,6 +2,8 @@ import { describe, expect, it } from "vitest";
2
2
 
3
3
  import type { Expect, Equal } from "@type-challenges/utils";
4
4
  import {
5
+ ifArray,
6
+ ifArrayPartial,
5
7
  ifBoolean,
6
8
  ifNumber,
7
9
  ifString,
@@ -9,9 +11,10 @@ import {
9
11
  ifUndefined,
10
12
  isTrue,
11
13
  } from "src/runtime/type-checks";
12
- import { EndsWith, StartsWith } from "src/types";
14
+ import { EndsWith, Extends, LowerAlpha, Or, StartsWith } from "src/types";
13
15
  import { ifStartsWith, startsWith } from "src/runtime/type-checks/startsWith";
14
16
  import { box } from "src/runtime/literals";
17
+ import { or } from "src/runtime";
15
18
 
16
19
  describe("runtime if/is", () => {
17
20
  it("ifString(v,i,e)", () => {
@@ -55,7 +58,7 @@ describe("runtime if/is", () => {
55
58
  type cases = [
56
59
  Expect<Equal<typeof t, 42>>, //
57
60
  Expect<Equal<typeof f, 42>>, //
58
- Expect<Equal<typeof f2, 42>> //
61
+ Expect<Equal<typeof f2, "yikes" | 42>> //
59
62
  ];
60
63
  const cases: cases = [true, true, true];
61
64
  });
@@ -115,6 +118,104 @@ describe("runtime if/is", () => {
115
118
  const cases: cases = [true, true];
116
119
  });
117
120
 
121
+ it("Or<T[]> type util", () => {
122
+ type T1 = Or<[true, true, false]>;
123
+ type T2 = Or<[false, false, false]>;
124
+ type T3 = Or<[boolean, boolean, true]>;
125
+ type T4 = Or<[boolean, boolean, boolean]>;
126
+
127
+ type cases = [
128
+ Expect<Equal<T1, true>>,
129
+ Expect<Equal<T2, false>>,
130
+ Expect<Equal<T3, true>>,
131
+ Expect<Equal<T4, boolean>>
132
+ ];
133
+ const cases: cases = [true, true, true, true];
134
+ });
135
+
136
+ it("or() runtime utility", () => {
137
+ const t1 = or(true, true, false);
138
+ const t2 = or(false, false, false);
139
+ const t3 = or(false as boolean, false, true);
140
+ const t4 = or(false as boolean, false as boolean, true as boolean);
141
+
142
+ type cases = [
143
+ Expect<Equal<typeof t1, true>>,
144
+ Expect<Equal<typeof t2, false>>,
145
+ Expect<Equal<typeof t3, true>>,
146
+ Expect<Equal<typeof t4, boolean>>
147
+ ];
148
+ const cases: cases = [true, true, true, true];
149
+
150
+ expect(t1).toBe(true);
151
+ expect(t2).toBe(false);
152
+ expect(t3).toBe(true);
153
+ expect(t4).toBe(true);
154
+ });
155
+
156
+ it("Extends<T,EXTENDS> with single clause", () => {
157
+ type cases = [
158
+ //
159
+ Expect<Equal<Extends<1, number>, true>>,
160
+ Expect<Equal<Extends<2, string>, false>>,
161
+ Expect<Equal<Extends<2, 2 | 3>, true>>
162
+ ];
163
+ const cases: cases = [true, true, true];
164
+ });
165
+
166
+ it("IfExtends<T,EXTENDS,IF,ELSE", () => {
167
+ type cases = [/** type tests */];
168
+ const cases: cases = [];
169
+ });
170
+
171
+ it("ifArray(val,if,else) utility", () => {
172
+ const fn0 = ifArray(
173
+ "foobar" as string,
174
+ (i) => `I'm an array, my length is ${i.length}` as const,
175
+ (i) => `I'm not an array, I am ${i}` as const
176
+ );
177
+ const fn1 = ifArray(
178
+ "foobar",
179
+ (i) => `I'm an array, my length is ${i.length}` as const,
180
+ (i) => `I'm not an array, I am ${i}` as const
181
+ );
182
+ const fn2 = ifArray(
183
+ ["foo", "bar"] as const,
184
+ (i) => `I'm an array, my length is ${i.length}` as const,
185
+ (i) => `I'm not an array, I am ${i}` as const
186
+ );
187
+
188
+ const fn3 = ifArray(
189
+ ["foo", "bar"],
190
+ (i) => `I'm an array, my length is ${i.length}` as const,
191
+ (i) => `I'm not an array, I am ${i}` as const
192
+ );
193
+
194
+ type cases = [
195
+ Expect<Equal<typeof fn0, `I'm not an array, I am ${string}`>>,
196
+ Expect<Equal<typeof fn1, `I'm not an array, I am foobar`>>,
197
+ Expect<Equal<typeof fn2, `I'm an array, my length is 2`>>,
198
+ Expect<Equal<typeof fn3, `I'm an array, my length is ${number}`>>
199
+ ];
200
+ const cases: cases = [true, true, true, true];
201
+ });
202
+
203
+ it("ifArrayPartial()()", () => {
204
+ const arrTest = ifArrayPartial<string | string[]>()(
205
+ (i) => `I'm an array, my length is ${i.length}`,
206
+ (i) => `I'm not an array, I am ${i}`
207
+ );
208
+
209
+ const t1 = arrTest("Bob");
210
+ const t2 = arrTest(["foo", "bar"]);
211
+
212
+ type cases = [
213
+ Expect<Equal<typeof t1, `I'm not an array, I am ${string}`>>,
214
+ Expect<Equal<typeof t2, `I'm an array, my length is ${number}`>>
215
+ ];
216
+ const cases: cases = [true, true];
217
+ });
218
+
118
219
  it("ifUndefined(v,i,e)", () => {
119
220
  const t = ifUndefined(undefined, 42, false);
120
221
  const f = ifUndefined(false, "yikes", 42);
@@ -135,14 +236,21 @@ describe("runtime if/is", () => {
135
236
  type T4 = StartsWith<string, "foo">;
136
237
  type T5 = StartsWith<string, string>;
137
238
 
239
+ type T6 = StartsWith<"alpha", LowerAlpha>;
240
+ type T7 = StartsWith<"Alpha", LowerAlpha>;
241
+
138
242
  type cases = [
139
243
  Expect<Equal<T1, true>>, //
140
244
  Expect<Equal<T2, false>>,
245
+ // if either the "start with" or "val" props are wide then we can't resolve at design time
141
246
  Expect<Equal<T3, boolean>>,
142
247
  Expect<Equal<T4, boolean>>,
143
- Expect<Equal<T5, boolean>>
248
+ Expect<Equal<T5, boolean>>,
249
+ // LowerAlpha is a string literal
250
+ Expect<Equal<T6, true>>,
251
+ Expect<Equal<T7, false>>
144
252
  ];
145
- const cases: cases = [true, true, true, true, true];
253
+ const cases: cases = [true, true, true, true, true, true, true];
146
254
  });
147
255
 
148
256
  it("EndsWith<T,U>", () => {
@@ -187,7 +295,7 @@ describe("runtime if/is", () => {
187
295
  // condition
188
296
  "foo",
189
297
  // inline
190
- (i) => `welcome ${i}` as const,
298
+ (i) => `welcome ${i}`,
191
299
  // external
192
300
  noSir
193
301
  );
@@ -1,22 +0,0 @@
1
- import { IfStringLiteral } from "src/types/type-checks";
2
-
3
- /**
4
- * **EndsWith**<T,U>
5
- *
6
- * A type utility which checks whether `T` _ends with_ the string literal `U`.
7
- *
8
- * If both `T` and `U` are string literals then the type system will resolve
9
- * to a literal `true` or `false` but if either is not a literal that it will
10
- * just resolve to `boolean` as the value can not be known at design time..
11
- */
12
- export type EndsWith<T extends unknown, U extends unknown> = T extends string
13
- ? U extends string
14
- ? T extends `${string}${U}`
15
- ? IfStringLiteral<
16
- T, //
17
- IfStringLiteral<U, true, boolean>,
18
- boolean
19
- >
20
- : IfStringLiteral<T, false, boolean>
21
- : false
22
- : false;
@@ -1,14 +0,0 @@
1
- /**
2
- * **Extends**
3
- *
4
- * Boolean type utility which returns `true` if `E` _extends_ `T`.
5
- */
6
- export type Extends<E, T> = E extends T ? true : false;
7
-
8
- /**
9
- * **IfExtends**
10
- *
11
- * Branching type utility which returns type `IF` when `E` _extends_ `T`; otherwise
12
- * it will return the type `ELSE`.
13
- */
14
- export type IfExtends<E, T, IF, ELSE> = Extends<E, T> extends true ? IF : ELSE;
@@ -1,16 +0,0 @@
1
- /**
2
- * **IsBooleanLiteral**
3
- *
4
- * Type utility which returns true/false if the boolean value is a _boolean literal_ versus
5
- * just the wider _boolean_ type.
6
- */
7
- export type IsBooleanLiteral<T extends boolean> = boolean extends T ? false : true;
8
-
9
- /**
10
- * **IfBooleanLiteral**
11
- *
12
- * Branch utility which returns `IF` type when `T` is a boolean literal and `ELSE` otherwise
13
- */
14
- export type IfBooleanLiteral<T extends boolean, IF, ELSE> = IsBooleanLiteral<T> extends true
15
- ? IF
16
- : ELSE;
@@ -1,16 +0,0 @@
1
- /**
2
- * **IsNumericLiteral**
3
- *
4
- * Type utility which returns true/false if the numeric value a _numeric literal_ versus
5
- * just the _number_ type.
6
- */
7
- export type IsNumericLiteral<T extends number> = number extends T ? false : true;
8
-
9
- /**
10
- * **IfNumericLiteral**
11
- *
12
- * Branch utility which returns `IF` type when `T` is a numeric literal and `ELSE` otherwise
13
- */
14
- export type IfNumericLiteral<T extends number, IF, ELSE> = IsNumericLiteral<T> extends true
15
- ? IF
16
- : ELSE;
@@ -1,14 +0,0 @@
1
- export type IsScalar<T> = [T] extends [string]
2
- ? true
3
- : [T] extends [number]
4
- ? true
5
- : [T] extends [boolean]
6
- ? true
7
- : false;
8
-
9
- /**
10
- * **IfScalar**
11
- *
12
- * Branch type utility which returns `IF` when `T` is a scalar value and `ELSE` otherwise
13
- */
14
- export type IfScalar<T, IF, ELSE> = IsScalar<T> extends true ? IF : ELSE;
@@ -1,14 +0,0 @@
1
- /**
2
- * **IsStringLiteral**
3
- *
4
- * Type utility which returns true/false if the string a _string literal_ versus
5
- * just the _string_ type.
6
- */
7
- export type IsStringLiteral<T> = [T] extends [string] ? (string extends T ? false : true) : false;
8
-
9
- /**
10
- * **IfStringLiteral**
11
- *
12
- * Branch utility which returns `IF` type when `T` is a string literal and `ELSE` otherwise
13
- */
14
- export type IfStringLiteral<T, IF, ELSE> = [IsStringLiteral<T>] extends [true] ? IF : ELSE;