inferred-types 0.34.2 → 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 (45) hide show
  1. package/README.md +2 -34
  2. package/dist/index.d.ts +1796 -1624
  3. package/dist/index.mjs +101 -18
  4. package/package.json +14 -13
  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 -0
  13. package/src/runtime/literals/pathJoin.ts +32 -0
  14. package/src/runtime/literals/stripLeading.ts +15 -0
  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 +52 -0
  27. package/src/types/alphabetic/StripLeading.ts +23 -0
  28. package/src/types/alphabetic/StripTrailing.ts +23 -0
  29. package/src/types/alphabetic/index.ts +4 -0
  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 +94 -0
  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 -852
package/dist/index.d.ts CHANGED
@@ -146,13 +146,13 @@ type Length<T extends readonly any[]> = T["length"];
146
146
  *
147
147
  * Type utility which tests whether two types -- `X` and `Y` -- are exactly the same type
148
148
  */
149
- type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
149
+ type IsEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
150
150
  /**
151
151
  * **NotEqual**`<X,Y>`
152
152
  *
153
153
  * Type utility which tests whether two types -- `X` and `Y` -- are _not_ exactly the same type
154
154
  */
155
- type NotEqual<X, Y> = true extends Equal<X, Y> ? false : true;
155
+ type NotEqual<X, Y> = true extends IsEqual<X, Y> ? false : true;
156
156
 
157
157
  /**
158
158
  * **AfterFirst**`<T>`
@@ -243,7 +243,7 @@ type Contains<T extends Narrowable, A extends readonly any[]> = First<A> extends
243
243
  * `true` if `T` _extends_ any element in `A` making it match widely against `A`. If you
244
244
  * prefer a wider match you can use `Contains<T,A>` instead.
245
245
  */
246
- type NarrowlyContains<T extends Narrowable, A extends readonly any[]> = Equal<First<A>, T> extends true ? true : [] extends AfterFirst<A> ? false : NarrowlyContains<T, AfterFirst<A>>;
246
+ type NarrowlyContains<T extends Narrowable, A extends readonly any[]> = IsEqual<First<A>, T> extends true ? true : [] extends AfterFirst<A> ? false : NarrowlyContains<T, AfterFirst<A>>;
247
247
 
248
248
  /**
249
249
  * Converts a Tuple type into a _union_ of the tuple elements
@@ -270,159 +270,191 @@ type LastInUnion<U> = UnionToIntersection<U extends unknown ? (x: U) => 0 : neve
270
270
  */
271
271
  type UnionToTuple<U, Last = LastInUnion<U>> = [U] extends [never] ? [] : [...UnionToTuple<Exclude<U, Last>>, Last];
272
272
 
273
- type Widen<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;
274
-
275
- type IsBoolean<T> = T extends boolean ? true : false;
273
+ declare function createFnWithProps<F extends Function, P extends {}>(fn: F, props: P): F & P;
276
274
  /**
277
- * Type utility which returns `true` or `false` based on
278
- * whether the type holds the narrow "true" type.
279
- * ```ts
280
- * // true
281
- * type T = IsTrue<true>;
282
- * // boolean
283
- * type U = IsTrue<boolean>;
284
- * // false
285
- * type F = IsTrue<false>;
286
- * type F2 = IsTrue<"false">;
287
- * ```
275
+ * Adds a dictionary of key/value pairs to a function.
288
276
  */
289
- type IsTrue<T extends Narrowable> = IsBoolean<T> extends true ? T extends true ? true : T extends false ? false : unknown : false;
290
- type IsFalse<T extends Narrowable> = IsBoolean<T> extends true ? T extends false ? true : true extends T ? false : unknown : false;
277
+ declare function fnWithProps<A extends any[], R extends any, P extends {}>(fn: ((...args: A) => R), props: P): ((...args: A) => R) & P;
291
278
  /**
292
- * Type utility which checks for literal `true` value and then switches type
293
- * to the IF, ELSE, or MAYBE generic types passed in where _maybe_ is when T
294
- * is the wide type of `boolean`
279
+ * Adds read-only (and narrowly typed) key/value pairs to a function
295
280
  */
296
- type IfTrue<T extends boolean, IF extends Narrowable, ELSE extends Narrowable, MAYBE extends Narrowable> = IsTrue<T> extends true ? IF : IsTrue<T> extends false ? ELSE : MAYBE;
281
+ declare function readonlyFnWithProps<A extends any[], R extends any, N extends Narrowable, P extends Record<keyof P, N>>(fn: ((...args: A) => R), props: P): ((...args: A) => R) & Readonly<P>;
282
+
297
283
  /**
298
- * Type utility which checks for literal `false` value and then switches type
299
- * to the IF, ELSE, or MAYBE generic types passed in where _maybe_ is when T
300
- * is the wide type of `boolean`
284
+ * Provides the _keys_ of an object with the `keyof T` made explicit.
301
285
  */
302
- type IfFalse<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable, MAYBE extends Narrowable> = IsFalse<T> extends true ? IF : IsTrue<T> extends false ? ELSE : MAYBE;
286
+ declare function keys<T extends {}, W extends readonly string[]>(obj: T, ...without: W): Length<W> extends 0 ? (keyof T)[] : Exclude<keyof T, Keys<W, undefined>>[];
287
+
303
288
  /**
304
- * **IsBooleanLiteral**
289
+ * **ruleSet**
305
290
  *
306
- * Type utility which returns true/false if the boolean value is a _boolean literal_ versus
307
- * just the wider _boolean_ type.
308
- */
309
- type IsBooleanLiteral<T extends Narrowable> = IsTrue<T> extends true ? true : IsFalse<T> extends true ? true : false;
310
- /**
311
- * **IfBooleanLiteral**
291
+ * Defines a ruleset composed of _dynamic_ and _static_ boolean operators.
312
292
  *
313
- * Branch utility which returns `IF` type when `T` is a boolean literal and `ELSE` otherwise
293
+ * - the first function call defines _dynamic_ props (_optional_)
294
+ * - the second function call defines static values
295
+ *
296
+ * ```ts
297
+ * const rs = ruleSet(
298
+ * r => r.state()( { maybe: r => r.extends({ foo: 1 }) })
299
+ * )(
300
+ * { color: true, age: false }
301
+ * );
302
+ * ```
314
303
  */
315
- type IfBooleanLiteral<T extends boolean, IF extends Narrowable, ELSE extends Narrowable> = IsBooleanLiteral<T> extends true ? IF : ELSE;
304
+ declare function ruleSet<N extends Narrowable, TState extends Record<keyof TState, N>>(defn?: TState): TState | undefined;
305
+
306
+ declare const api: <N extends Narrowable, TPrivate extends Readonly<Record<any, N>>>(priv: TPrivate) => <TPublic extends object>(pub: TPublic) => () => TPublic;
316
307
 
317
308
  /**
318
- * **IsStringLiteral**
309
+ * A type utility which looks at a chain for functions and reduces the type
310
+ * to the final `ReturnType` of the chain.
319
311
  *
320
- * Type utility which returns true/false if the string a _string literal_ versus
321
- * just the _string_ type.
312
+ * ```ts
313
+ * // number
314
+ * type T = FinalReturn<() => (foo: string) => (bar: string) => () => number>;
315
+ * ```
322
316
  */
323
- type IsStringLiteral<T extends Narrowable> = [T] extends [string] ? string extends T ? false : true : false;
317
+ type FinalReturn<T extends any> = T extends (...args: any[]) => any ? FinalReturn<ReturnType<T>> : T;
318
+
324
319
  /**
325
- * **IfStringLiteral**
326
- *
327
- * Branch utility which returns `IF` type when `T` is a string literal and `ELSE` otherwise
320
+ * A function which returns a boolean value
328
321
  */
329
- type IfStringLiteral<T extends string, IF extends Narrowable, ELSE extends Narrowable> = [
330
- IsStringLiteral<T>
331
- ] extends [true] ? IF : ELSE;
322
+ type LogicFunction<T extends readonly any[]> = (...args: T) => boolean;
323
+
332
324
  /**
333
- * **IsNumericLiteral**
325
+ * Groups a number of "logic functions" together by combining their results using
326
+ * the logical **AND** operator.
334
327
  *
335
- * Type utility which returns true/false if the numeric value a _numeric literal_ versus
336
- * just the _number_ type.
328
+ * **Note:** a "logic function" is any function which returns a boolean
337
329
  */
338
- type IsNumericLiteral<T extends number> = number extends T ? false : true;
330
+ declare const and: <T extends any[]>(...ops: readonly LogicFunction<T>[]) => LogicFunction<T>;
331
+
339
332
  /**
340
- * **IfNumericLiteral**
333
+ * **Or**`<T>`
341
334
  *
342
- * Branch utility which returns `IF` type when `T` is a numeric literal and `ELSE` otherwise
335
+ * Takes an array of boolean values and produces a boolean OR across these values
343
336
  */
344
- type IfNumericLiteral<T extends number, IF extends Narrowable, ELSE extends Narrowable> = IsNumericLiteral<T> extends true ? IF : ELSE;
337
+ type Or<T extends readonly boolean[]> = NarrowlyContains<true, T> extends true ? true : NarrowlyContains<boolean, T> extends true ? boolean : false;
338
+
339
+ declare function or<O extends readonly boolean[]>(...conditions: O): Or<O>;
340
+
345
341
  /**
346
- * **IsLiteral**
342
+ * Groups a number of "logic functions" together by combining their results using
343
+ * the logical **NOT** operator.
347
344
  *
348
- * Type utility which returns true/false if the value passed -- a form of a
349
- * string, number, or boolean -- is a _literal_ value of that type (true) or
350
- * the more generic wide type (false).
345
+ * **Note:** a "logic function" is any function which returns a boolean
351
346
  */
352
- type IsLiteral<T> = [T] extends [string] ? IsStringLiteral<T> : [T] extends [boolean] ? IsBooleanLiteral<T> : [T] extends [number] ? IsNumericLiteral<T> : false;
347
+ declare const not: <T extends any[]>(op: LogicFunction<T>) => LogicFunction<T>;
348
+
349
+ type FilterStarts = {
350
+ /** one or more string which the value is allowed to start with */
351
+ startsWith: string | string[];
352
+ };
353
+ type FilterIs = {
354
+ /** whether a string _**is**_ of a particular value */
355
+ is: string | string[];
356
+ };
357
+ type FilterEnds = {
358
+ endsWith: string | string[];
359
+ };
360
+ type FilterContains = {
361
+ /** whether any of the strings specified are _contained_ in the value */
362
+ contains: string | string[];
363
+ };
364
+ type FilterEquals = {
365
+ /** one or more values which _equal_ the value passed in */
366
+ equals: number | number[];
367
+ };
368
+ type FilterNotEqual = {
369
+ /** one or more values which ALL _do not equal_ the value passed in */
370
+ notEqual: number | number[];
371
+ };
372
+ type FilterGreaterThan = {
373
+ /** the incoming value is greater than this value */
374
+ greaterThan: number;
375
+ };
376
+ type FilterLessThan = {
377
+ /** the incoming value is less than this value */
378
+ lessThan: number;
379
+ };
380
+ type StringFilter = FilterIs | FilterStarts | FilterEnds | FilterContains | (FilterStarts & FilterEnds) | (FilterStarts & FilterContains) | (FilterEnds & FilterContains) | (FilterStarts & FilterEnds & FilterContains);
381
+ type NumericFilter = FilterEquals | FilterNotEqual | FilterGreaterThan | FilterLessThan | (FilterEquals & FilterNotEqual) | (FilterEquals & FilterGreaterThan) | (FilterEquals & FilterLessThan) | (FilterNotEqual & FilterGreaterThan) | (FilterNotEqual & FilterLessThan) | (FilterGreaterThan & FilterLessThan) | (FilterEquals & FilterGreaterThan & FilterLessThan) | (FilterNotEqual & FilterGreaterThan & FilterLessThan) | (FilterEquals & FilterNotEqual & FilterGreaterThan & FilterLessThan);
382
+ type FilterDefn = StringFilter | NumericFilter;
383
+ type NotFilter = {
384
+ /**
385
+ * **not**
386
+ *
387
+ * If you want to build a filter who's conditions being met results in _filtering_
388
+ * the value rather than accepting it then choose this.
389
+ */
390
+ not: FilterDefn;
391
+ };
392
+ declare function isNotFilter(f: FilterDefn | NotFilter): f is NotFilter;
393
+ type UnwrapNot<T extends FilterDefn | NotFilter> = T extends NotFilter ? T["not"] extends StringFilter ? StringFilter : NumericFilter : T;
394
+ declare function isNumericFilter(filter: FilterDefn): filter is NumericFilter;
395
+ type UndefinedValue<U extends boolean> = true extends U ? "undefined treated as 'true'" : U extends "no-impact" ? "undefined treated in no-impact fashion" : "undefined treated as 'false'";
396
+ type UndefinedTreatment = "undefined treated as 'true'" | "undefined treated as 'false'";
397
+ type LogicalCombinator = "AND" | "OR";
353
398
  /**
354
- * **IsOptionalLiteral**
355
- *
356
- * Type utility which returns true/false if the value passed -- a form of a
357
- * string, number, or boolean -- is a _literal_ value of that type (true) or
358
- * the more generic wide type (false).
399
+ * **FilterFn**
359
400
  *
360
- * This type also strips off _undefined_ from any possible union type to evaluate
361
- * to `true` even when a literal value is in union with _undefined_. If you don't
362
- * want to test for the union with _undefined_ use the `IsOptional` utility instead.
401
+ * A filter function derived from the `filter()` configurator. This function is intended to provide a type-strong _filter_ function which can be used like so:
402
+ * be used like:
403
+ * ```ts
404
+ * const onlyPrivate = filter({ startsWith: "_" });
405
+ * const privateFiles = files.filter(onlyPrivate);
406
+ * ```
363
407
  */
364
- type IsOptionalLiteral<T> = [Exclude<T, undefined>] extends [string] ? IsStringLiteral<Exclude<T, undefined>> : [Exclude<T, undefined>] extends [boolean] ? IsBooleanLiteral<Exclude<T, undefined>> : [Exclude<T, undefined>] extends [number] ? IsNumericLiteral<Exclude<T, undefined>> : false;
408
+ type FilterFn<T extends StringFilter | NumericFilter> = T extends StringFilter ? <V extends string | undefined>(input: V) => boolean : <V extends number | undefined>(input: V) => boolean;
365
409
  /**
366
- * **IfLiteral**
367
- *
368
- * Branch type utility with return `IF` when `T` is a _literal_ value and `ELSE` otherwise
410
+ * Defines a logical function for each condition type
369
411
  */
370
- type IfLiteral<T, IF extends Narrowable, ELSE extends Narrowable> = IsLiteral<T> extends true ? IF : ELSE;
412
+ type ConditionFilter<T extends StringFilter | NumericFilter> = T extends StringFilter ? (input: string) => boolean : (input: number) => boolean;
371
413
  /**
372
- * **IfOptionalLiteral**
414
+ * **filter**
373
415
  *
374
- * Branch type utility with return `IF` when `T` is a _literal_ value (with possibly
375
- * the inclusion of _undefined_); otherwise returns the type `ELSE`
376
- */
377
- type IfOptionalLiteral<T, IF extends Narrowable, ELSE extends Narrowable> = IsOptionalLiteral<T> extends true ? IF : ELSE;
378
-
379
- /**
380
- * **Includes**`<TSource, TValue>`
416
+ * A higher order helper utility which builds a boolean _filter_ function based on a simple
417
+ * configuration object. Support either _string_ or _numeric_ filters.
381
418
  *
382
- * Type utility which returns `true` or `false` based on whether `TValue` is found
383
- * in `TSource`. Where `TSource` can be a string literal or an array of string literals.
419
+ * ```ts
420
+ * const str = filter({startsWith: ["_", "."], endsWith: ".md"});
421
+ * const num = filter({ greaterThan: 55, notEqual: [66, 77]});
422
+ * ```
384
423
  *
385
- * **Note:** if the source is a _wide_ type (aka, `string` or `string[]`) then there is
386
- * no way to know at design-time whether the value includes `TValue` and so it will return
387
- * a type of `boolean`.
388
- */
389
- type Includes<TSource extends string | readonly string[], TValue extends string> = TSource extends string[] ? IsStringLiteral<TupleToUnion<TSource>> extends true ? IsLiteral<TValue> extends true ? TValue extends TupleToUnion<TSource> ? true : false : boolean : boolean : TSource extends string ? IsLiteral<TSource> extends true ? IsLiteral<TValue> extends true ? TSource extends `${string}${TValue}${string}` ? true : false : boolean : boolean : boolean;
390
-
391
- type IsScalar<T extends Narrowable> = [T] extends [string] ? true : [T] extends [number] ? true : [T] extends [boolean] ? true : false;
392
- /**
393
- * **IfScalar**`<T, IF, ELSE>`
424
+ * All conditions (e.g., `startsWith`, `contains`, `notEqual`, etc.) that a particular filter
425
+ * is defined as having -- if there is more than one -- will be logically combined using AND
426
+ * unless specified otherwise in the third parameter.
394
427
  *
395
- * Branch type utility which returns `IF` when `T` is a scalar value (aka, string, number, or boolean) and `ELSE` otherwise
428
+ * How a value of _undefined_ will be treated is stated in the second parameter but defaults
429
+ * to "no-impact" which means it's `false` when the logicCombinator is OR but defaults
430
+ * to `true` when the logicCombinator is AND.
396
431
  */
397
- type IfScalar<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable> = IsScalar<T> extends true ? IF : ELSE;
432
+ declare const filter: <F extends FilterDefn | NotFilter, U extends boolean | "no-impact", C extends LogicalCombinator>(config: F, logicCombinator?: C, ifUndefined?: U) => FilterFn<UnwrapNot<F>>;
398
433
 
399
434
  /**
400
- * **IsUndefined**
401
- *
402
- * Boolean type utility returns `true` if `T` is undefined; `false` otherwise
403
- */
404
- type IsUndefined<T extends Narrowable> = T extends undefined ? true : false;
405
- /**
406
- * **IfUndefined**`<T, IF, ELSE>`
435
+ * Passing in an array of strings, you are passed back a dictionary with
436
+ * all the keys being the strings and values set to `true`.
437
+ * ```ts
438
+ * // { bar: true, bar: true } as const;
439
+ * const d - dictArr(arr);
407
440
  *
408
- * Type utility which returns `IF` type when `T` is an _undefined_
409
- * otherwise returns `ELSE` type.
441
+ * const fooBar = arrayToKeyLookup("foo", "bar");
442
+ * ```
410
443
  */
411
- type IfUndefined<T, IF extends Narrowable, ELSE extends Narrowable> = IsUndefined<T> extends true ? IF : ELSE;
444
+ declare function arrayToKeyLookup<T extends readonly string[]>(...keys: T): Record<T[number], true>;
412
445
 
413
- /**
414
- * **Extends**`<T, EXTENDS>`
415
- *
416
- * Boolean type utility which returns `true` if `T` _extends_ `EXTENDS`.
417
- */
418
- type Extends<T extends Narrowable, EXTENDS extends Narrowable> = T extends EXTENDS ? true : false;
419
- /**
420
- * **IfExtends**
421
- *
422
- * Branching type utility which returns type `IF` when `E` _extends_ `T`; otherwise
423
- * it will return the type `ELSE`.
424
- */
425
- type IfExtends<T extends Narrowable, EXTENDS extends Narrowable, IF extends Narrowable, ELSE extends Narrowable> = Extends<T, EXTENDS> extends true ? IF : ELSE;
446
+ interface DefinePropertiesApi<T extends {}> {
447
+ /**
448
+ * Makes a property on the object **readonly** on the Javascript runtime
449
+ */
450
+ ro<K extends keyof T>(prop: K, errorMsg?: (p: K, v: any) => string): Omit<T, K> & Record<K, Readonly<T[K]>>;
451
+ /**
452
+ * Makes a property on the object **read/writeable** on the Javascript runtime;
453
+ * this is the default so only use this where it is needed.
454
+ */
455
+ rw<K extends keyof T>(prop: K): Omit<T, K> & Record<K, Readonly<T[K]>>;
456
+ }
457
+ declare function defineProperties<T extends {}>(obj: T): DefinePropertiesApi<T>;
426
458
 
427
459
  /**
428
460
  * Often when mutating the shape of an object you will end up with the union of a number of
@@ -433,2005 +465,1789 @@ type IfExtends<T extends Narrowable, EXTENDS extends Narrowable, IF extends Narr
433
465
  type SimplifyObject<T extends {}> = ExpandRecursively<UnionToIntersection<ExpandRecursively<T>>>;
434
466
 
435
467
  /**
436
- * **TypeDefault**
437
- *
438
- * A type utility designed to help maintain strong and narrow types where
439
- * you have a value `T` which _might_ be **undefined** and a type `D` which
440
- * defines all the _default_ type for `T`.
441
- *
442
- * - In all cases we compare first whether `T` is undefined and replace it's
443
- * type with `D` 1-for-1 if it is
444
- * - To address a larger set of use cases, when `D` _extends_ an object we will
445
- * compare each property of `D` against `T`
468
+ * Given a dictionary of key/values, where the value is a function, this
469
+ * type utility will maintain the keys but change the values to whatever
470
+ * the `ReturnType` of the function was.
446
471
  * ```ts
447
- * type I = { foo?: "foo" | undefined; bar?: 42 | 53 | undefined };
448
- * type D = { foo: "foo"; bar: 53 };
449
- * type DF = TypeDefault<I,D>; // `D`
450
- * const i = { foo: undefined, bar: 99 } as const;
451
- * type DF2 = TypeDefault<typeof i, D>; // `{ foo: "foo"; bar: 99 }`
472
+ * const api = {
473
+ * val: 42,
474
+ * hi: (name: string) => `hi ${name}`,
475
+ * bye: (name: string) => `bye ${name}`
476
+ * };
477
+ * // { hi: string; bye: string }
478
+ * type Test = UnwrapValue<typeof api>
479
+ * // { val: number; foo: string; bar: string }
480
+ * type Test2 = UnwrapValue<typeof api, false>
452
481
  * ```
453
482
  */
454
- type TypeDefault<T, D> = IsObject<D> extends true ? IsObject<T> extends true ? SimplifyObject<{
455
- [K in keyof D]: K extends keyof T ? TypeDefault<T[K], D[K]> : D[K];
456
- }> : IfUndefined<T, // check if T is undefined
457
- D, // use D as the type
458
- Exclude<T, undefined>> : IfUndefined<T, // check whether is T is undefined
459
- D, // assign to D if it is
460
- IfOptionalLiteral<T, // if T is a literal
461
- IfExtends<D, T, D, // use D since it extends the value of T
462
- Exclude<T, undefined>>, Exclude<T, undefined>>>;
463
-
464
- /**
465
- * **IsObject**
466
- *
467
- * Boolean type utility used to check whether a type `T` is an object
468
- */
469
- type IsObject<T> = Mutable<T> extends Record<string, any> ? T extends FunctionType ? false : Mutable<T> extends any[] ? false : true : false;
470
- /**
471
- * **IfObject**
472
- *
473
- * Branch type utility with return `IF` when `T` extends an object type
474
- * and `ELSE` otherwise
475
- */
476
- type IfObject<T, IF extends Narrowable, ELSE extends Narrowable> = IsObject<T> extends true ? IF : ELSE;
483
+ type DictPartialApplication<T extends Record<string, any>, I extends boolean = true> = SimplifyObject<{
484
+ [K in keyof T]: T[K] extends (...args: any[]) => any ? Record<K, ReturnType<T[K]>> : true extends I ? never : Record<K, T[K]>;
485
+ }[keyof T]>;
477
486
 
478
487
  /**
479
- * **StartsWith**<TValue, TStartsWith>
488
+ * Allow a dictionary have it's value's type changed to `T` while maintaining the keys in
489
+ * the original object `I` so long as the original value for the KV pair extends `V`.
480
490
  *
481
- * A type utility which checks whether `T` _starts with_ the string literal `U`.
491
+ * If `V` is not specified then it defaults to _any_ and therefore all KVs are preserved.
482
492
  *
483
- * If both `T` and `U` are string literals then the type system will resolve
484
- * to a literal `true` or `false` but if either is not a literal that it will
485
- * just resolve to `boolean` as the value can not be known at design time..
493
+ * ```ts
494
+ * type Obj = { foo: "hello", bar: 42, baz: () => "world" };
495
+ * // { foo: number, bar: number, baz: number };
496
+ * type AllNumbers = DictChangeValue<Obj, number>;
497
+ * // { foo: number }
498
+ * type StringToBool = DictChangeValue<Obj, boolean, string>
499
+ * ```
486
500
  */
487
- type StartsWith<TValue extends string, TStartsWith extends string> = IsStringLiteral<TStartsWith> extends true ? IsStringLiteral<TValue> extends true ? TValue extends `${TStartsWith}${string}` ? true : false : boolean : boolean;
501
+ type DictChangeValue<
502
+ /** the object who's value-type we're changing */
503
+ I extends Record<string, any>,
504
+ /** the return type that functions should be modified to have */
505
+ T extends any,
488
506
  /**
489
- * **IfStartsWith**<TValue, TStartsWith, IF, ELSE, MAYBE>
490
- *
491
- * Type utility which converts type to `IF` type _if_ TValue _starts with_ `TStartsWith` but
492
- * otherwise converts type to `ELSE`.
493
- *
494
- * Note, that there is also an optional `MAYBE` type
495
- * which can be stated for cases where TValue or TStartsWith _might_ be the wider `string`
496
- * type and therefore the type is unknown at design time.
507
+ *The type we expect in the value; if the value extends type `V` then the value will
508
+ * be converted to type `O`; if not then the KV pair will be discarded
497
509
  */
498
- type IfStartsWith<TValue extends string, TStartsWith extends string, IF extends Narrowable, ELSE extends Narrowable> = StartsWith<TValue, TStartsWith> extends true ? IF : StartsWith<TValue, TStartsWith> extends false ? ELSE : IF | ELSE;
510
+ V extends any = any> = SimplifyObject<{
511
+ [K in keyof I]: I[K] extends V ? Record<K, T> : never;
512
+ }[keyof I]>;
499
513
 
500
514
  /**
501
- * **EndsWith**<T,U>
502
- *
503
- * A type utility which checks whether `T` _ends with_ the string literal `U`.
515
+ * **DictPrependWithFn**
504
516
  *
505
- * If both `T` and `U` are string literals then the type system will resolve
506
- * to a literal `true` or `false` but if either is not a literal that it will
507
- * just resolve to `boolean` as the value can not be known at design time..
508
- */
509
- type EndsWith<TValue extends string, TEndsWith extends string> = IsStringLiteral<TEndsWith> extends true ? IsStringLiteral<TValue> extends true ? TValue extends `${string}${TEndsWith}` ? true : false : boolean : boolean;
510
- /**
511
- * **IfEndsWith**<TValue, TEndsWith, IF, ELSE, MAYBE>
517
+ * Given a strongly typed object `<T>`, this utility will inject a function call with
518
+ * arguments `<A>` and then return what had subsequently been the value of the property.
512
519
  *
513
- * Type utility which converts type to `IF` type _if_ `TValue` _ends with_ `TEndsWith` but
514
- * otherwise converts type to `ELSE`. If there are wide types in the mix then the type will
515
- * result in the union of IF and ELSE.
520
+ * Should you only want to apply this treatment to _some_ of the properties you can
521
+ * pass in a value `<E>` which will ensure that only properties which _extend_ `E` will be
522
+ * modified.
516
523
  */
517
- type IfEndsWith<TValue extends string, TEndsWith extends string, IF extends Narrowable, ELSE extends Narrowable> = EndsWith<TValue, TEndsWith> extends true ? IF : EndsWith<TValue, TEndsWith> extends false ? ELSE : IF | ELSE;
524
+ type DictPrependWithFn<T extends Record<string, any>, A extends any[], E extends any = any> = SimplifyObject<{
525
+ [K in keyof T]: T[K] extends E ? Record<K, (...args: A) => T[K]> : Record<K, T[K]>;
526
+ }[keyof T]>;
518
527
 
519
528
  /**
520
- * **Or**`<T>`
529
+ * **DictReturnValues**
521
530
  *
522
- * Takes an array of boolean values and produces a boolean OR across these values
531
+ * A type utility which receives an object `<T>` and then modifies
532
+ * the return type of any properties which are a function to have this
533
+ * new **ReturnType** `<R>`. Optionally you can specify a particular return type which
534
+ * you are targeting and then
523
535
  */
524
- type Or<T extends readonly boolean[]> = NarrowlyContains<true, T> extends true ? true : NarrowlyContains<boolean, T> extends true ? boolean : false;
536
+ type DictReturnValues<
537
+ /** the object which we expect to have props with function values */
538
+ T extends Record<string, any>,
539
+ /** the return type that functions should be modified to have */
540
+ R extends any,
541
+ /** optionally this utility can target only functions with a certain existing return value */
542
+ O extends (...args: any[]) => any = (...args: any[]) => any> = SimplifyObject<{
543
+ [K in keyof T]: T[K] extends O ? T[K] extends (...args: infer A) => any ? Record<K, (...args: A) => R> : Record<K, T[K]> : Record<K, T[K]>;
544
+ }[keyof T]>;
525
545
 
526
546
  /**
527
- * Makes a readonly structure mutable
547
+ * Expresses whether an option is "opt" (optional) or "req" (required)
528
548
  */
529
- type Mutable<T> = {
530
- -readonly [K in keyof T]: IsObject<T[K]> extends true ? Mutable<T[K]> : T[K];
531
- };
549
+ type OptRequired = "opt" | "req";
532
550
 
551
+ declare const DEFAULT_ONE_TO_MANY_MAPPING: FinalizedMapConfig<"req", "I -> O[]", "opt">;
552
+ declare const DEFAULT_ONE_TO_ONE_MAPPING: FinalizedMapConfig<"req", "I -> O", "req">;
553
+ declare const DEFAULT_MANY_TO_ONE_MAPPING: FinalizedMapConfig<"req", "I[] -> O", "req">;
554
+ type DefaultOneToManyMapping = typeof DEFAULT_ONE_TO_MANY_MAPPING;
555
+ type DefaultOneToOneMapping = typeof DEFAULT_ONE_TO_ONE_MAPPING;
556
+ type DefaultManyToOneMapping = typeof DEFAULT_MANY_TO_ONE_MAPPING;
533
557
  /**
534
- * Provides a negation of a type of the type `T` _not_ `U`.
535
- * ```ts
536
- * const foo = 42;
537
- * // 33
538
- * type NotTheMeaningOfLife = Not<33, 42>;
539
- * // never
540
- * type NotTheMeaningOfLife = Not<42, 42>;
541
- * ```
558
+ * **mapTo** _utility_
542
559
  *
543
- * Note: same as `Exclude`
544
- */
545
- type Not<T, U> = T extends U ? never : T;
546
-
547
- type Digital = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
548
- type MakeArray<S extends string, T extends any[] = []> = S extends `${T["length"]}` ? T : MakeArray<S, [...T, 0]>;
549
- type Multiply10<T extends any[]> = [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T];
550
- /**
551
- * Converts a string literal to a numeric literal
560
+ * This utility -- by default -- creates a strongly typed 1:M data mapper which maps from one
561
+ * known source `I` to any array of another `O[]`:
552
562
  * ```ts
553
- * // 0
554
- * type Zero = Numeric<"0">;
555
- * // 10
556
- * type Ten = Numeric<"10">;
563
+ * const mapper = mapTo<I, O>(i => [{
564
+ * foo: i.bar
565
+ * }]);
557
566
  * ```
558
567
  */
559
- type Numeric<S extends string, T extends any[] = []> = S extends `${infer S1}${infer S2}` ? S1 extends Digital ? Numeric<S2, [...Multiply10<T>, ...MakeArray<S1>]> : never : T["length"];
560
-
568
+ declare const mapToFn: ConfiguredMap<DefaultOneToManyMapping>["map"];
561
569
  /**
562
- * **Opaque**
563
- *
564
- * Create an opaque type, which hides its internal details from the public, and
565
- * can only be created by being used explicitly.
566
- *
567
- * Note: taken from [type-fest](https://github.com/sindresorhus/type-fest/blob/main/source/opaque.d.ts)
568
- * repo.
570
+ * Provides a `config` method which allows the relationships between _inputs_
571
+ * and _outputs_ to be configured.
569
572
  */
570
- type Opaque<Type, Token = unknown> = Type & {
571
- readonly __opaque__: Token;
572
- };
573
-
573
+ declare const mapToDict: MapperApi;
574
574
  /**
575
- * **Retain<T, K>**
575
+ * **mapTo** _utility_
576
576
  *
577
- * Reduces the type system to just the key/values which are represented in `K`.
578
- * The `L` generic can largely be ignored unless you need _literal_ equality.
577
+ * This utility creates a strongly typed data mapper which maps from one
578
+ * known source `I` to another `O`.
579
579
  *
580
+ * Signatures:
580
581
  * ```ts
581
- * type Obj = { foo: 1, bar: number, baz: string };
582
- * // { foo: 1, bar: number }
583
- * type Retained = Retain<Obj, "foo" | "bar">;
582
+ * const defMap = mapTo<I,O>( ... );
583
+ * const configured = mapTo.config({ output: "req" }).map<I,O>( ... );
584
+ * const one2one = mapTo.oneToOne().map<I,O>( ... );
585
+ * const many2one = mapTo.manyToOne().map<I,O>( ... );
584
586
  * ```
585
- *
586
- * **Note:** in essence this is the _opposite_ of `Exclude<T,K>`
587
- */
588
- type Retain<T, K extends keyof T> = Pick<T, Include<keyof T, K>>;
589
-
590
- /**
591
- * **SameKeys**
592
- *
593
- * Creates a _type_ with the same _keys_ as `T` but sets all values of these keys to `A` (which is
594
- * **any** by default).
595
- *
596
- * Note: meant to be used as part of an _extends_ clause in most cases.
597
587
  */
598
- type SameKeys<T extends object, A extends any = any> = {
599
- [P in keyof T]: A;
600
- };
588
+ declare const mapTo: (<I, O>(map: (source: I) => O[]) => Mapper<I, O, FinalizedMapConfig<"req", "I -> O[]", "opt">>) & MapperApi;
601
589
 
602
590
  /**
603
- * **Transformer**
604
- *
605
- * A function responsible for transforming the _values_ of
606
- * dictionary `I` into different _values_ for dictionary `O`.
591
+ * **Extends**`<T, EXTENDS>`
607
592
  *
608
- * This type utility assumes that _keys_ of both dictionaries
609
- * are the same.
593
+ * Boolean type utility which returns `true` if `T` _extends_ `EXTENDS`.
610
594
  */
611
- type Transformer<I extends object, O extends SameKeys<I>, K extends keyof I = keyof I> = (input: I, key: K) => O[K];
612
-
595
+ type Extends<T extends Narrowable, EXTENDS extends Narrowable> = T extends EXTENDS ? true : false;
613
596
  /**
614
- * **TypeGuard**
597
+ * **IfExtends**
615
598
  *
616
- * a typing for a **TS** type-guard which evaluates an _unknown_ input
617
- * and determines if it is of type `T`.
599
+ * Branching type utility which returns type `IF` when `E` _extends_ `T`; otherwise
600
+ * it will return the type `ELSE`.
618
601
  */
619
- type TypeGuard<T> = (thing: unknown) => thing is T;
602
+ type IfExtends<T extends Narrowable, EXTENDS extends Narrowable, IF extends Narrowable, ELSE extends Narrowable> = Extends<T, EXTENDS> extends true ? IF : ELSE;
620
603
 
604
+ type IsBoolean<T> = [T] extends [boolean] ? true : false;
621
605
  /**
622
- * Allows filtering down `T` to those which extend a given type `U`.
623
- *
624
- * - `T` is either a dictionary (where keys will be used to compare) or
625
- * a readonly sting array.
606
+ * Type utility which returns `true` or `false` based on
607
+ * whether the type holds the narrow "true" type.
626
608
  * ```ts
627
- * const arr = ["foo", "bar", "baz"];
628
- * // "bar" | "baz"
629
- * type BA = Where<typeof arr, `ba${string}`>;
609
+ * // true
610
+ * type T = IsTrue<true>;
611
+ * // boolean
612
+ * type U = IsTrue<boolean>;
613
+ * // false
614
+ * type F = IsTrue<false>;
615
+ * type F2 = IsTrue<"false">;
630
616
  * ```
631
617
  */
632
- type Where<T extends Record<string, any> | readonly string[], U> = T extends readonly string[] ? Include<T[number], U> : {
633
- [K in keyof T]: K extends U ? K : never;
634
- }[keyof T];
618
+ type IsTrue<T extends Narrowable> = IsBoolean<T> extends true ? T extends true ? true : T extends false ? false : unknown : false;
619
+ type IsFalse<T extends Narrowable> = IsBoolean<T> extends true ? T extends false ? true : true extends T ? false : unknown : false;
635
620
  /**
636
- * Allows filtering down `T` to those which extend a given type `U`.
637
- *
638
- * - `T` is either a dictionary (where keys will be used to compare) or
639
- * a readonly sting array.
640
- * ```ts
641
- * const arr = ["foo", "bar", "baz"];
642
- * // "foo"
643
- * type F = WhereNot<typeof arr, `ba${string}`>;
644
- * ```
645
- */
646
- type WhereNot<T extends Record<string, any> | readonly string[], U> = T extends readonly string[] ? Exclude<T[number], U> : {
647
- [K in keyof T]: K extends U ? never : K;
648
- }[keyof T];
649
-
650
- type AppendToObject<T, U extends keyof any, V> = {
651
- [K in keyof T | U]: K extends keyof T ? T[K] : V;
652
- };
653
- /**
654
- * Appends a new Key/Value to an existing dictionary <T>
655
- */
656
- type AppendToDictionary<TDict, TKey extends string, TValue> = {
657
- [K in keyof TDict | TKey]: K extends keyof TDict ? TDict[K] : TValue;
658
- };
659
-
660
- /**
661
- * Accepts the `true` literal or _undefined_.
662
- */
663
- type MaybeTrue = true | undefined;
664
- /**
665
- * Accepts the `false` literal or _undefined_.
621
+ * Type utility which checks for literal `true` value and then switches type
622
+ * to the IF, ELSE, or MAYBE generic types passed in where _maybe_ is when T
623
+ * is the wide type of `boolean`
666
624
  */
667
- type MaybeFalse = false | undefined;
668
-
625
+ type IfTrue<T extends boolean, IF extends Narrowable, ELSE extends Narrowable, MAYBE extends Narrowable> = IsTrue<T> extends true ? IF : IsTrue<T> extends false ? ELSE : MAYBE;
669
626
  /**
670
- * A conditional clause used in the application of the `ifTypeOf` utility
627
+ * Type utility which checks for literal `false` value and then switches type
628
+ * to the IF, ELSE, or MAYBE generic types passed in where _maybe_ is when T
629
+ * is the wide type of `boolean`
671
630
  */
672
- type ExtendsClause<N extends Narrowable, TValue extends Record<keyof TValue, N> | number | string | boolean | symbol> = <TBase extends any>(base: TBase) => TValue extends TBase ? true : false;
631
+ type IfFalse<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable, MAYBE extends Narrowable> = IsFalse<T> extends true ? IF : IsTrue<T> extends false ? ELSE : MAYBE;
673
632
  /**
674
- * A conditional clause used in the application of the `ifTypeOf` utility
633
+ * **IsBooleanLiteral**
634
+ *
635
+ * Type utility which returns true/false if the boolean value is a _boolean literal_ versus
636
+ * just the wider _boolean_ type.
675
637
  */
676
- type ExtendsNarrowlyClause<N extends Narrowable, TValue extends Record<keyof TValue, N> | number | string | boolean | symbol> = <NB extends Narrowable, TBase extends Record<keyof TBase, NB> | number | string | boolean | symbol>(base: TBase) => TValue extends TBase ? true : false;
638
+ type IsBooleanLiteral<T extends Narrowable> = IsTrue<T> extends true ? true : IsFalse<T> extends true ? true : false;
677
639
  /**
678
- * **TypeCondition**
679
- *
680
- * A partially applied type from the `ifTypeOf` utility where the base type has been
681
- * defined and we now need to express the type which is intended to extend it.
640
+ * **IfBooleanLiteral**
682
641
  *
683
- * - `extends` - compares with _wide_ types
684
- * - `narrowlyExtends` - compares with _narrow_ / _literal_ types
642
+ * Branch utility which returns `IF` type when `T` is a boolean literal and `ELSE` otherwise
685
643
  */
686
- type TypeCondition<N extends Narrowable, TValue extends Record<keyof TValue, N> | number | string | boolean | symbol> = {
687
- extends: ExtendsClause<N, TValue>;
688
- narrowlyExtends: ExtendsNarrowlyClause<N, TValue>;
689
- };
644
+ type IfBooleanLiteral<T extends boolean, IF extends Narrowable, ELSE extends Narrowable> = IsBooleanLiteral<T> extends true ? IF : ELSE;
690
645
 
691
- type LowerAlpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z";
692
- /** Uppercase alphabetic character */
693
- type UpperAlpha = Uppercase<LowerAlpha>;
694
646
  /**
695
- * Alphabetical characters (upper and lower)
647
+ * **IsStringLiteral**
648
+ *
649
+ * Type utility which returns true/false if the string a _string literal_ versus
650
+ * just the _string_ type.
696
651
  */
697
- type Alpha = UpperAlpha | LowerAlpha;
698
- type Whitespace = " " | "\n" | "\t";
699
- type Punctuation = "." | "," | ";" | "!" | "?";
652
+ type IsStringLiteral<T extends Narrowable> = [T] extends [string] ? string extends T ? false : true : false;
700
653
  /**
701
- * Characters which typically are used to separate words (but not including a space)
654
+ * **IfStringLiteral**
655
+ *
656
+ * Branch utility which returns `IF` type when `T` is a string literal and `ELSE` otherwise
702
657
  */
703
- type StringDelimiter = "_" | "-" | "/" | "\\";
704
- type OpeningBracket = "(" | "[" | "{";
705
- type ClosingBracket = ")" | "]" | "}";
658
+ type IfStringLiteral<T extends string, IF extends Narrowable, ELSE extends Narrowable> = [
659
+ IsStringLiteral<T>
660
+ ] extends [true] ? IF : ELSE;
706
661
  /**
707
- * Opening and closing parenthesis
662
+ * **IsNumericLiteral**
663
+ *
664
+ * Type utility which returns true/false if the numeric value a _numeric literal_ versus
665
+ * just the _number_ type.
708
666
  */
709
- type Parenthesis = "(" | ")";
667
+ type IsNumericLiteral<T extends number> = number extends T ? false : true;
710
668
  /**
711
- * Opening and closing brackets
669
+ * **IfNumericLiteral**
670
+ *
671
+ * Branch utility which returns `IF` type when `T` is a numeric literal and `ELSE` otherwise
712
672
  */
713
- type Bracket = OpeningBracket | ClosingBracket;
673
+ type IfNumericLiteral<T extends number, IF extends Narrowable, ELSE extends Narrowable> = IsNumericLiteral<T> extends true ? IF : ELSE;
714
674
  /**
715
- * Numeric string characters
675
+ * **IsLiteral**
676
+ *
677
+ * Type utility which returns true/false if the value passed -- a form of a
678
+ * string, number, or boolean -- is a _literal_ value of that type (true) or
679
+ * the more generic wide type (false).
716
680
  */
717
- type NumericString = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
681
+ type IsLiteral<T> = [T] extends [string] ? IsStringLiteral<T> : [T] extends [boolean] ? IsBooleanLiteral<T> : [T] extends [number] ? IsNumericLiteral<T> : false;
718
682
  /**
719
- * Any alphabetic or numeric string character
683
+ * **IsOptionalLiteral**
684
+ *
685
+ * Type utility which returns true/false if the value passed -- a form of a
686
+ * string, number, or boolean -- is a _literal_ value of that type (true) or
687
+ * the more generic wide type (false).
688
+ *
689
+ * This type also strips off _undefined_ from any possible union type to evaluate
690
+ * to `true` even when a literal value is in union with _undefined_. If you don't
691
+ * want to test for the union with _undefined_ use the `IsOptional` utility instead.
720
692
  */
721
- type AlphaNumeric = Alpha | NumericString;
693
+ type IsOptionalLiteral<T> = [Exclude<T, undefined>] extends [string] ? IsStringLiteral<Exclude<T, undefined>> : [Exclude<T, undefined>] extends [boolean] ? IsBooleanLiteral<Exclude<T, undefined>> : [Exclude<T, undefined>] extends [number] ? IsNumericLiteral<Exclude<T, undefined>> : false;
722
694
  /**
723
- * Allows alphanumeric characters and some special characters typically allowed
724
- * in variable names.
695
+ * **IfLiteral**
696
+ *
697
+ * Branch type utility with return `IF` when `T` is a _literal_ value and `ELSE` otherwise
725
698
  */
726
- type VariableName = AlphaNumeric | "_" | "." | "-";
727
- type SpecialCharacters = "@" | "~" | "^" | "#" | "&" | "*";
699
+ type IfLiteral<T, IF extends Narrowable, ELSE extends Narrowable> = IsLiteral<T> extends true ? IF : ELSE;
728
700
  /**
729
- * Non-alphabetic characters including whitespace, string numerals, and
701
+ * **IfOptionalLiteral**
702
+ *
703
+ * Branch type utility with return `IF` when `T` is a _literal_ value (with possibly
704
+ * the inclusion of _undefined_); otherwise returns the type `ELSE`
730
705
  */
731
- type NonAlpha = Whitespace | Punctuation | NumericString | Bracket | SpecialCharacters;
732
- type Ipv4 = `${number}.${number}.${number}.${number}`;
706
+ type IfOptionalLiteral<T, IF extends Narrowable, ELSE extends Narrowable> = IsOptionalLiteral<T> extends true ? IF : ELSE;
733
707
 
734
708
  /**
735
- * Extracts the _required_ keys in the object's type. You also may
736
- * optionally filter by the _value_ of the key.
737
- */
738
- type RequiredKeys<T extends object, V extends any = any> = {
739
- [K in keyof T]-?: {} extends {
740
- [P in K]: T[K];
741
- } ? never : T[K] extends V ? K : never;
742
- }[keyof T];
743
- /**
744
- * Extracts the intersecting/common keys to two objects
709
+ * **IsUndefined**
710
+ *
711
+ * Boolean type utility returns `true` if `T` is undefined; `false` otherwise
745
712
  */
746
- type IntersectingKeys<T extends Record<string, any> | readonly string[], U extends Record<string, any> | readonly string[]> = {
747
- [K in keyof T]: K extends Keys<U> ? K : never;
748
- }[keyof T];
713
+ type IsUndefined<T extends Narrowable> = T extends undefined ? true : false;
749
714
  /**
750
- * Extracts the _optional_ keys in the object's type. You also may
751
- * optionally filter by the _value_ of the key.
715
+ * **IfUndefined**`<T, IF, ELSE>`
716
+ *
717
+ * Type utility which returns `IF` type when `T` is an _undefined_
718
+ * otherwise returns `ELSE` type.
752
719
  */
753
- type OptionalKeys<T extends object, V extends any = any> = {
754
- [K in keyof T]-?: {} extends {
755
- [P in K]: T[K];
756
- } ? V extends T[K] ? K : never : never;
757
- }[keyof T];
720
+ type IfUndefined<T, IF extends Narrowable, ELSE extends Narrowable> = IsUndefined<T> extends true ? IF : ELSE;
721
+
758
722
  /**
759
- * The _keys_ on a given object `T` which have a literal value of `W`.
723
+ * **TypeDefault**
760
724
  *
761
- * Optionally, you may provide a generic `E` to exclude certain keys in
762
- * result set.
725
+ * A type utility designed to help maintain strong and narrow types where
726
+ * you have a value `T` which _might_ be **undefined** and a type `D` which
727
+ * defines all the _default_ type for `T`.
728
+ *
729
+ * - In all cases we compare first whether `T` is undefined and replace it's
730
+ * type with `D` 1-for-1 if it is
731
+ * - To address a larger set of use cases, when `D` _extends_ an object we will
732
+ * compare each property of `D` against `T`
763
733
  * ```ts
764
- * // "foo"
765
- * type Str = KeysWithValue<{ foo: "hi"; bar: 5 }>;
734
+ * type I = { foo?: "foo" | undefined; bar?: 42 | 53 | undefined };
735
+ * type D = { foo: "foo"; bar: 53 };
736
+ * type DF = TypeDefault<I,D>; // `D`
737
+ * const i = { foo: undefined, bar: 99 } as const;
738
+ * type DF2 = TypeDefault<typeof i, D>; // `{ foo: "foo"; bar: 99 }`
766
739
  * ```
767
740
  */
768
- type KeysWithValue<W extends any, T extends object> = {
769
- [K in keyof T]: T[K] extends W ? Readonly<K> : never;
770
- }[keyof T];
741
+ type TypeDefault<T, D> = IsObject<D> extends true ? IsObject<T> extends true ? SimplifyObject<{
742
+ [K in keyof D]: K extends keyof T ? TypeDefault<T[K], D[K]> : D[K];
743
+ }> : IfUndefined<T, // check if T is undefined
744
+ D, // use D as the type
745
+ Exclude<T, undefined>> : IfUndefined<T, // check whether is T is undefined
746
+ D, // assign to D if it is
747
+ IfOptionalLiteral<T, // if T is a literal
748
+ IfExtends<D, T, D, // use D since it extends the value of T
749
+ Exclude<T, undefined>>, Exclude<T, undefined>>>;
750
+
771
751
  /**
772
- * A `PrivateKey` must start with a `_` character and then follow with
773
- * an alphabetic character
752
+ * Expresses relationship between inputs/outputs:
774
753
  */
775
- type PrivateKey = `_${Alpha}${string}`;
754
+ declare enum MapCardinality {
755
+ /** every input results in 0:M outputs */
756
+ OneToMany = "I -> O[]",
757
+ /** every input results in 0:1 outputs */
758
+ OneToOne = "I -> O",
759
+ /** every input is an array of type I and reduced to a single O */
760
+ ManyToOne = "I[] -> O"
761
+ }
762
+ type MapCardinalityIllustrated = EnumValues<MapCardinality>;
776
763
  /**
777
- * Keys on an object which have a `_` character as first part of the
778
- * name are considered private and this utility will create a union
779
- * of all the keys in this category.
764
+ * The _user_ configuration of a **mapTo** mapper function
765
+ * which will be finalized by merging it with the appropriate
766
+ * default mapping type.
780
767
  */
781
- type PrivateKeys<T extends object> = {
782
- [K in keyof T]: K extends `_${string}` ? K : never;
783
- }[keyof T];
768
+ interface MapConfig<IR extends OptRequired | undefined = undefined, D extends MapCardinalityIllustrated | undefined = undefined, OR extends OptRequired | undefined = undefined> {
769
+ input?: IR;
770
+ output?: OR;
771
+ cardinality?: D;
772
+ /**
773
+ * Whether calls to the final `MapFn` will be logged to stderr
774
+ * for debugging purposes. Defaults to false; if you specify
775
+ * a _string_ for a value that will be sent to stderr along
776
+ * with other debugging info.
777
+ */
778
+ debug?: boolean | string;
779
+ }
784
780
  /**
785
- * **PublicKeys**
781
+ * A finalized configuration of a **mapTo** mapper functions cardinality
782
+ * relationships between _inputs_ and _outputs_.
786
783
  *
787
- * Builds a union type of all keys which are "public" where a public
788
- * key is any key which _does not_ start with the `_` character.
784
+ * Note: _this configuration does _not_ yet include the actual mapping
785
+ * configuration between the input and output._
789
786
  */
790
- type PublicKeys<T extends object> = {
791
- [K in keyof T]: K extends `_${string}` ? never : K;
792
- }[keyof T];
793
- type StringKeys<T extends object> = {
794
- [K in keyof T]: K extends string ? Readonly<K> : never;
795
- }[keyof T];
787
+ type FinalizedMapConfig<IR extends OptRequired = MapIR<DefaultOneToManyMapping>, D extends MapCardinalityIllustrated = MapCard<DefaultOneToManyMapping>, OR extends OptRequired = MapOR<DefaultOneToManyMapping>> = Required<Omit<MapConfig<IR, D, OR>, "debug">> & {
788
+ finalized: true;
789
+ debug: boolean | string;
790
+ };
796
791
  /**
797
- * The keys of an object which _are not_ a string type
792
+ * User configuration exposed by a config function which specifies the
793
+ * cardinality already (e.g., `oneToMany()`, `manyToOne()`)
798
794
  */
799
- type NonStringKeys<T extends object> = {
800
- [K in keyof T]: K extends string ? never : Readonly<K>;
801
- }[keyof T];
802
- type NumericKeys<T extends object> = {
803
- [K in keyof T]: K extends number ? Readonly<K> : never;
804
- }[keyof T];
805
- type NonNumericKeys<T extends object> = {
806
- [K in keyof T]: K extends number ? never : Readonly<K>;
807
- }[keyof T];
808
- /**
809
- * **RequiredProps**
810
- *
811
- * Reduces an object type to only key/value pairs where the key is required
812
- */
813
- type RequiredProps<T extends object> = Pick<T, RequiredKeys<T>>;
814
- /**
815
- * **OptionalProps**
816
- *
817
- * Reduces an object to only key/value pairs where the key is optional
818
- */
819
- type OptionalProps<T extends object> = Pick<T, OptionalKeys<T>>;
795
+ type MapCardinalityConfig<IR extends OptRequired | undefined, OR extends OptRequired | undefined> = {
796
+ /** whether we the input can _optionally_ be an `undefined` value or not */
797
+ input?: IR;
798
+ /** whether we the output can _optionally_ be an `undefined` value or not */
799
+ output?: OR;
800
+ /**
801
+ * Whether calls to the final `MapFn` will be logged to stderr
802
+ * for debugging purposes. Defaults to false; if you set to a string
803
+ * value than this will be echoed out with stderr.
804
+ */
805
+ debug?: boolean | string;
806
+ };
820
807
  /**
821
- * **WithValue**
808
+ * **ConfiguredMap**
822
809
  *
823
- * Reduces an object's type down to only those key/value pairs where the
824
- * value is of type `W`.
825
- * ```ts
826
- * const foo = { a: 1, b: "hi", c: () => "hello" }
827
- * // { c: () => "hello" }
828
- * type W = WithValue<Function, typeof foo>
829
- * ```
810
+ * A partial application of the mapTo() utility which has expressed the
811
+ * configuration of the _inputs_ and _outputs_ and provides a `.map()`
812
+ * method which allows the user configure the specifics of the mapping.
830
813
  */
831
- type WithValue<W extends any, T extends object, E extends any = undefined> = undefined extends E ? Pick<T, KeysWithValue<W, T>> : Omit<Pick<T, KeysWithValue<W, T>>, KeysWithValue<E, T>>;
814
+ type ConfiguredMap<C extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = {
815
+ map: <I, O>(map: MapTo<I, O, C>) => Mapper<I, O, C>;
816
+ input: MapIR<C>;
817
+ cardinality: MapCard<C>;
818
+ output: MapOR<C>;
819
+ debug: boolean | string;
820
+ };
832
821
  /**
833
- * Reduces an object to only the key/value pairs where the key is a
834
- * string.
822
+ * Extracts the IR, Cardinality, and OR generics from a FinalizedMapConfig
835
823
  */
836
- type WithStringKeys<T extends object> = Omit<T, NonStringKeys<T>>;
824
+ type DecomposeMapConfig<M extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = M extends MapConfig<infer IR, infer D, infer OR> ? IR extends OptRequired | undefined ? D extends MapCardinalityIllustrated | undefined ? OR extends OptRequired | undefined ? [IR, D, OR] : never : never : never : M extends FinalizedMapConfig<infer IR, infer D, infer OR> ? IR extends OptRequired ? D extends MapCardinalityIllustrated ? OR extends OptRequired ? [IR, D, OR] : never : never : never : never;
825
+ /** extracts IR from a `FinalizedMapConfig` */
826
+ type MapIR<T extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = DecomposeMapConfig<T>[0];
837
827
  /**
838
- * Reduces an object to only the key/value pairs where the key is numeric.
828
+ * extracts the MapCardinality from a `FinalizedMapConfig`
839
829
  */
840
- type WithNumericKeys<T extends object> = Omit<T, NonNumericKeys<T>>;
841
-
830
+ type MapCard<T extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = DecomposeMapConfig<T>[1];
831
+ /** extracts OR from a `FinalizedMapConfig` */
832
+ type MapOR<T extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = DecomposeMapConfig<T>[2];
842
833
  /**
843
- * **RuleDefinition**
844
- *
845
- * A rule definition is the typing for the fluent API surface that is built up
846
- * with the **ruleset** utility.
834
+ * Merges the types of a userland configuration with a default configuration
847
835
  */
848
- type RuleDefinition<
849
- /** the data which will be evaluated on rule execution */
850
- T extends object,
851
- /** the optional props -- as a union type -- which must be defined per the rule */
852
- H extends string = "",
853
- /** the key/values which will be evaluated on execution (wide type) */
854
- E extends Partial<SameKeys<T>> = {},
855
- /** the key/values which will be evaluated on execution (narrow type) */
856
- N extends Partial<SameKeys<T>> = {}> = {
836
+ type AsFinalizedConfig<U extends MapConfig<OptRequired | undefined, MapCardinalityIllustrated | undefined, OptRequired | undefined>, D extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = TypeDefault<U, D> extends FinalizedMapConfig<infer IR, infer C, infer OR> ? FinalizedMapConfig<IR, C, OR> : never;
837
+ type MapperApi = {
857
838
  /**
858
- * sets up a true/false check that a given property is defined; this
859
- * condition can only be applied to _optional_ properties.
839
+ * Provides opportunity to configure _input_, _output_, and _cardinality_
840
+ * prior to providing a mapping function.
841
+ *
842
+ * Note: _the defaults for configuration are defined by the_ `DEFAULT_ONE_TO_MANY_MAPPING`
843
+ * _constant made available as a symbol from this library._
860
844
  */
861
- has(optProp: OptionalKeys<T>): RuleDefinition<T, H & typeof optProp, E, N>;
845
+ config: <C extends MapConfig<OptRequired, //
846
+ MapCardinalityIllustrated, OptRequired>>(config: C) => ConfiguredMap<AsFinalizedConfig<C, //
847
+ DefaultOneToManyMapping>>;
862
848
  /**
863
- * Validates that a given property extends a certain value's type; comparison
864
- * is made assuming "wide types".
849
+ * Provides a nice 1:1 ratio between the input and output.
850
+ *
851
+ * By default the input and output are considered to be _required_
852
+ * properties but this can be changed with the options hash provided.
853
+ * ```ts
854
+ * const mapper = mapTo.oneToOne().map(...);
855
+ * // add in ability to filter out some inputs
856
+ * const mapAndFilter = mapTo.oneToOne({ output: "opt" })
857
+ * ```
865
858
  */
866
- equals<K extends keyof T, V extends Pick<T, K>>(prop: K, value: V): RuleDefinition<T, H, E & Record<K, V>, N>;
859
+ oneToOne: <C extends MapCardinalityConfig<OptRequired, OptRequired>>(config?: C) => ConfiguredMap<AsFinalizedConfig<C, //
860
+ DefaultOneToOneMapping>>;
867
861
  /**
868
- * Validates that a given property extends a certain value's type; comparison
869
- * is made assuming "narrow types". This is only available for props which
870
- * expose a
862
+ * **manyToOne** _mapping_
863
+ *
864
+ * Provides a configuration where multiple inputs `I[]` will be mapped to a
865
+ * single output `O`.
866
+ *
867
+ * Choosing this configuration will, by default, set both input and output
868
+ * to be "required" but you can change this default if you so choose.
871
869
  */
872
- narrowlyEquals<K extends keyof T, V extends Pick<T, K>>(prop: K, value: V): RuleDefinition<T, H, E, N & Record<K, V>>;
870
+ manyToOne: <C extends MapCardinalityConfig<OptRequired | undefined, //
871
+ //
872
+ OptRequired | undefined>>(config?: C) => ConfiguredMap<AsFinalizedConfig<C, //
873
+ DefaultManyToOneMapping>>;
874
+ oneToMany: <C extends MapCardinalityConfig<OptRequired | undefined, //
875
+ //
876
+ OptRequired | undefined>>(config?: C) => ConfiguredMap<AsFinalizedConfig<C, //
877
+ DefaultOneToManyMapping>>;
873
878
  };
879
+ type MapInput<I, //
880
+ IR extends OptRequired, C extends MapCardinalityIllustrated> = C extends MapCardinality.OneToMany | "I -> O[]" ? IR extends "opt" ? I | undefined : I : C extends MapCardinality.OneToOne | "I -> O" ? IR extends "opt" ? I | undefined : I : C extends MapCardinality.ManyToOne | "I[] -> O" ? IR extends "opt" ? I[] | undefined : I[] : never;
881
+ type MapOutput<O, //
882
+ OR extends OptRequired, C extends MapCardinalityIllustrated> = C extends MapCardinality.OneToMany | "I -> O[]" ? OR extends "opt" ? O[] : [O, ...O[]] : C extends MapCardinality.OneToOne | "I -> O" ? OR extends "opt" ? O | null : O : C extends MapCardinality.ManyToOne | "I[] -> O" ? OR extends "opt" ? O | null : O : never;
874
883
  /**
875
- * **DynamicRule**
884
+ * **MapTo<I, O>**
876
885
  *
877
- * A dynamic rule allows type and runtime validation of a data structure
878
- * which extends a known `State`. It then returns the literal type `true`
879
- * or `false`.
886
+ * A mapping function between an input type `I` and output type `O`. Defaults to using
887
+ * the _default_ OneToMany mapping config.
880
888
  *
881
- * ```ts
882
- * type State = { id?: string; favorite: boolean; color: string };
883
- * // type-safe way to check whether optional prop is actually set
884
- * const rule: DynamicRule<State> = s => s
885
- * .has("id")
886
- * .equals("favorite", true)
887
- * .equals("color", "red");
888
- * ```
889
+ * **Note:** this type is designed to guide the userland mapping; refer
890
+ * to `MapFn` if you want the type output by the `mapFn()` utility.
889
891
  */
890
- type DynamicRule<TState extends any, TResult extends true | false> = (rule: TypeCondition<any, TState>) => TResult;
892
+ type MapTo<I, O, C extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired> = DefaultOneToManyMapping> = MapIR<C> extends "opt" ? (source?: MapInput<I, MapIR<C>, MapCard<C>>) => MapOutput<O, MapOR<C>, MapCard<C>> : (source: MapInput<I, MapIR<C>, MapCard<C>>) => MapOutput<O, MapOR<C>, MapCard<C>>;
893
+ type MapFnOutput<I, O, S, OR extends OptRequired, C extends MapCardinalityIllustrated> = C extends "I -> O[]" | MapCardinality.OneToMany ? S extends I[] ? OR extends "opt" ? O[] : [O, ...O[]] : OR extends "opt" ? O[] | null : O[] : C extends MapCardinality.OneToOne | "I -> O" ? S extends I[] ? OR extends "opt" ? O[] : [O, ...O[]] : OR extends "opt" ? O | null : O : C extends MapCardinality.ManyToOne | "I[] -> O" ? S extends I[][] ? OR extends "opt" ? O[] : [O, ...O[]] : OR extends "opt" ? O | null : O : never;
894
+ type MapFnInput<I, IR extends OptRequired, D extends MapCardinalityIllustrated> = D extends "I -> O[]" | MapCardinality.OneToMany ? IR extends "opt" ? I | I[] | undefined : I | I[] : D extends MapCardinality.OneToOne | "I -> O" ? IR extends "opt" ? I | I[] | undefined : I | I[] : D extends MapCardinality.ManyToOne | "I[] -> O" ? IR extends "opt" ? I[] | I[][] | undefined : I[] | I[][] : never;
891
895
  /**
892
- * **DynamicRuleSet**
896
+ * The mapping function provided by the `mapFn()` utility. This _fn_
897
+ * is intended to be used in two ways:
893
898
  *
894
- * A function which accepts the agreed `TState` generic as input and returns a discrete
895
- * `true` or `false` value.
899
+ * 1. Iterative:
900
+ * ```ts
901
+ * const m = mapTo<I,O>(i => [ ... ]);
902
+ * // maps inputs to outputs
903
+ * const out = inputs.map(m);
904
+ * ```
905
+ * 2. Block:
906
+ * ```ts
907
+ * // maps inputs to outputs (filtering or splitting where appr.)
908
+ * const out2 = m(inputs);
909
+ * ```
896
910
  */
897
- type DynamicRuleSet<TState extends any, TRules extends Record<string, TypeCondition<any, TState>>> = (rules: TRules) => true | false;
898
-
899
- type RuntimeType<T> = {
900
- __kind: "type";
901
- type: T;
902
- is: TypeGuard<T>;
903
- };
904
- type RuntimeProp<P extends Readonly<PropertyKey>, T extends RuntimeType<any>> = {
905
- __kind: "prop";
906
- key: Readonly<P>;
907
- valueType: Readonly<T["type"]>;
911
+ type MapFn<I, O, C extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = MapIR<C> extends "opt" ? <S extends MapFnInput<I, MapIR<C>, MapCard<C>>>(source?: S) => MapFnOutput<I, O, S, MapOR<C>, MapCard<C>> : <S extends MapFnInput<I, MapIR<C>, MapCard<C>>>(source: S) => MapFnOutput<I, O, S, MapOR<C>, MapCard<C>>;
912
+ /**
913
+ * **Mapper**
914
+ *
915
+ * A fully configured _mapper_ stemming from the **mapTo()** utility. It is both a mapping
916
+ * function and a dictionary which describes the mapper's properties.
917
+ * ```ts
918
+ * const m = mapTo.oneToOne().map( ... );
919
+ * const mapped = m(inputs);
920
+ * const mappedOver = inputs.map(m);
921
+ * ```
922
+ *
923
+ * Note: the root of a `Mapper` is the mapper function but
924
+ * this is combined with a dictionary of settings and types
925
+ * which you can use. For instance, look at the `fnSignature`
926
+ * property to get the _type_ signature of the map function.
927
+ */
928
+ type Mapper<I = unknown, O = unknown, C extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired> = FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = {
929
+ input: MapIR<C>;
930
+ output: MapOR<C>;
931
+ cardinality: MapCard<C>;
932
+ debug: boolean | string;
933
+ inputType: I;
934
+ outputType: O;
908
935
  /**
909
- * Provides the _type_ to the type system when used with `typeof`.
910
- *
911
- * ```ts
912
- * const t = number();
913
- * // number
914
- * type T = typeof t.type;
915
- * ```
936
+ * Provides the _type_ information for mapper function.
916
937
  *
917
- * **Note:** _the runtime system will get a string equivalent name:_
918
- * ```ts
919
- * const t = number();
920
- * // "number"
921
- * console.log(t.type);
922
- * ```
938
+ * Note: _this is just a **type**_ not the actual function which positioned
939
+ * at the root of the Mapper type
923
940
  */
924
- type: Record<P, T["type"]>;
925
- is: TypeGuard<Record<P, T["type"]>>;
926
- };
927
- type TypeOptions<T extends Partial<object> = {}> = {
928
- /** each type has a default type guard but you can override if you need to be more specific */
929
- typeGuard?: TypeGuard<T>;
930
- } & T;
931
-
941
+ fnSignature: MapFn<I, O, C>;
942
+ } & MapFn<I, O, C>;
932
943
  /**
933
- * Validates that a given type extends another and returns `true` or `false` type
944
+ * **MapInputFrom**
945
+ *
946
+ * Type utility which extracts the `I` type from a fully configured `Mapper`
934
947
  */
935
- type ExpectExtends<VALUE, EXPECTED> = EXPECTED extends VALUE ? true : false;
948
+ type MapInputFrom<T extends Mapper> = T extends Mapper<infer I> ? I : never;
936
949
  /**
937
- * Validates that a given type extends another and returns `any` or `never` as a type
950
+ * **MapOutputFrom**
951
+ *
952
+ * Type utility which extracts the output [`O`] type from a fully configured `Mapper`
938
953
  */
939
- type AssertExtends<VALUE, EXPECTED> = EXPECTED extends VALUE ? any : never;
954
+ type MapOutputFrom<T extends Mapper> = T extends Mapper<any, infer O> ? O : never;
940
955
  /**
941
- * Give a type `TValue` and a comparison type `TExtends`
956
+ * **MapCardinalityFrom**
957
+ *
958
+ * Type utility which extracts _cardinality_ of a `Mapper`'s inputs to outputs
942
959
  */
943
- type IfExtendsThen<VALUE, EXPECTED, THEN> = EXPECTED extends VALUE ? THEN : never;
960
+ type MapCardinalityFrom<T extends Mapper> = T extends Mapper<any, any, infer C> ? C extends FinalizedMapConfig<OptRequired, infer Cardinality, OptRequired> ? Cardinality : never : never;
944
961
 
945
962
  /**
946
- * Indicates whether `T` has _all_ uppercase characters in it.
963
+ * Given a dictionary of type `<T>`, this utility function will
964
+ * make the `<M>` generic property _mutable_ and all other _read-only_.
965
+ *
947
966
  * ```ts
948
- * // true
949
- * type T = AllCaps<"FOOBAR">;
950
- * // false
951
- * type T = AllCaps<"FooBar">;
952
- * // "unknown"
953
- * type T = AllCaps<string>;
967
+ * // { foo: string, bar?: Readonly<number> }
968
+ * type Example = MutableProps<{
969
+ * foo: Readonly<string>,
970
+ * bar?: number
971
+ * }, "foo">;
954
972
  * ```
955
973
  */
956
- type AllCaps<T extends string> = string extends T ? "unknown" : T extends Uppercase<T> ? true : false;
974
+ type MutableProps<T extends {}, M extends keyof T & string> = ExpandRecursively<Mutable<Pick<T, M>> & Readonly<Pick<T, Keys<T, M>>>>;
957
975
 
958
976
  /**
959
- * **Break<T,D>**
960
- *
961
- * Takes a string `T`, and splits it into a tuple of the form `[F, R]`.
962
- * ```ts
963
- * // ["the", " long and winding road"]
964
- * type T1 = Break<"the long and winding road", " ">;
965
- * // ["there", " I was, there I was"]
966
- * type T2 = Break<"there I was, there I was", " ">;
967
- * ```
968
- */
969
- type Break<T extends string, D extends string> = (string extends T ? [string, string] : (T extends `${infer F}${D}${infer _R}` ? (F extends `${infer _X}${D}${infer _Y}` ? never : (T extends `${F}${infer R}` ? [F, R] : never)) : [T, ""]));
970
-
971
- /**
972
- * Concatenates two arrays (of literals).
977
+ * Given a dictionary of type `<T>`, this utility function will
978
+ * make the `<R>` generic property _required_ (use a union to make
979
+ * more than one prop required).
980
+ *
973
981
  * ```ts
974
- * // [ "foo", "bar", "baz" ]
975
- * type T = ArrConcat<["foo"], ["bar", "baz"]>;
982
+ * // { foo: string, bar?: number }
983
+ * type Example = RequireProps<{foo?: string, bar?: number}, "foo">;
976
984
  * ```
977
985
  */
978
- type ArrConcat<A extends any[], B extends any[]> = [...A, ...B];
986
+ type RequireProps<T extends {}, R extends keyof T> = ExpandRecursively<Required<Pick<T, R>> & T>;
979
987
 
980
988
  /**
981
- * Type utility which takes a string `S` and replaces the substring `W` with `P`.
982
- * ```ts
983
- * const fooy = "fooy";
984
- * // "Foo"
985
- * type Foo = Replace<typeof fooy, "y", "">;
986
- * ```
989
+ * **SameKeys**
987
990
  *
988
- * Note: _the first match is replaced and all subsequent matches are ignored_
991
+ * Creates a _type_ with the same _keys_ as `T` but sets all values of these keys to `A` (which is
992
+ * **any** by default).
993
+ *
994
+ * Note: meant to be used as part of an _extends_ clause in most cases.
989
995
  */
990
- type Replace<S extends string, W extends string, P extends string> = S extends "" ? "" : W extends "" ? S : S extends `${infer F}${W}${infer E}` ? `${F}${P}${E}` : S;
996
+ type SameKeys<T extends object, A extends any = any> = {
997
+ [P in keyof T]: A;
998
+ };
991
999
 
1000
+ type LowerAlpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z";
1001
+ /** Uppercase alphabetic character */
1002
+ type UpperAlpha = Uppercase<LowerAlpha>;
992
1003
  /**
993
- * Trims off whitespace on left of string
994
- * ```ts
995
- * // "foobar "
996
- * type T = TrimLeft<"\n\t foobar ">;
997
- * // string
998
- * type T = TrimLeft<string>;
999
- * ```
1004
+ * Alphabetical characters (upper and lower)
1000
1005
  */
1001
- type TrimLeft<S extends string> = string extends S ? string : S extends `${Whitespace}${infer Right}` ? TrimLeft<Right> : S;
1002
-
1006
+ type Alpha = UpperAlpha | LowerAlpha;
1007
+ type Whitespace = " " | "\n" | "\t";
1008
+ type Punctuation = "." | "," | ";" | "!" | "?";
1003
1009
  /**
1004
- * Provides the _left_ whitespace of a string
1005
- * ```ts
1006
- * // "\n\t "
1007
- * type T = LeftWhitespace<"\n\t foobar">;
1008
- * ```
1010
+ * Characters which typically are used to separate words (but not including a space)
1009
1011
  */
1010
- type LeftWhitespace<S extends string> = string extends S ? string : Replace<S, TrimLeft<S>, "">;
1011
-
1012
+ type StringDelimiter = "_" | "-" | "/" | "\\";
1013
+ type OpeningBracket = "(" | "[" | "{";
1014
+ type ClosingBracket = ")" | "]" | "}";
1012
1015
  /**
1013
- * Trims off whitespace on left of string
1014
- * ```ts
1015
- * // "\n foobar"
1016
- * type T = TrimRight<"\n foobar \t">;
1017
- * // string
1018
- * type T = TrimRight<string>;
1019
- * ```
1016
+ * Opening and closing parenthesis
1020
1017
  */
1021
- type TrimRight<S extends string> = string extends S ? string : S extends `${infer Right}${Whitespace}` ? TrimRight<Right> : S;
1022
-
1018
+ type Parenthesis = "(" | ")";
1023
1019
  /**
1024
- * Provides the _left_ whitespace of a string
1025
- * ```ts
1026
- * // "\n\t "
1027
- * type T = LeftWhitespace<"\n\t foobar">;
1028
- * ```
1020
+ * Opening and closing brackets
1029
1021
  */
1030
- type RightWhitespace<S extends string> = string extends S ? string : Replace<S, TrimRight<S>, "">;
1031
-
1022
+ type Bracket = OpeningBracket | ClosingBracket;
1032
1023
  /**
1033
- * Type utility that provides the _length_ of a given string type in a way which
1034
- * is _not_ limited to TS's recursive string length of roughly 48.
1035
- *
1036
- * ```ts
1037
- * // 3
1038
- * type Three = StringLength<"foo">;
1039
- * ```
1024
+ * Numeric string characters
1040
1025
  */
1041
- type StringLength<S extends string, R extends number[] = []> = S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}${infer _Sixth}${infer _Sevebnth}${infer _Eighth}${infer _Ninth}${infer _Tenth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}${infer _Sixth}${infer _Sevebnth}${infer _Eighth}${infer _Ninth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}${infer _Sixth}${infer _Sevebnth}${infer _Eighth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}${infer _Sixth}${infer _Sevebnth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}${infer _Sixth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer Rest}` ? StringLength<Rest, [...R, 1, 1]> : S extends `${infer _First}${infer Rest}` ? StringLength<Rest, [...R, 1]> : [...R]["length"];
1042
-
1026
+ type NumericString = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
1043
1027
  /**
1044
- * Trims off blank spaces, `\n` and `\t` characters from both sides of a _string literal_.
1045
- * ```ts
1046
- * // "foobar"
1047
- * type T = Trim<"\n\t foobar ">;
1048
- * // string
1049
- * type T = Trim<string>;
1050
- * ```
1028
+ * Any alphabetic or numeric string character
1051
1029
  */
1052
- type Trim<S extends string> = string extends S ? string : S extends `${Whitespace}${infer Right}` ? Trim<Right> : S extends `${infer Left}${Whitespace}` ? Trim<Left> : S;
1053
-
1030
+ type AlphaNumeric = Alpha | NumericString;
1054
1031
  /**
1055
- * An email address
1032
+ * Allows alphanumeric characters and some special characters typically allowed
1033
+ * in variable names.
1056
1034
  */
1057
- type Email = `${string}@${string}.${string}`;
1058
- type Zip5 = `${NumericString}${NumericString}${string}${NumericString}`;
1059
- type Zip4 = `${NumericString}${string}`;
1035
+ type VariableName = AlphaNumeric | "_" | "." | "-";
1036
+ type SpecialCharacters = "@" | "~" | "^" | "#" | "&" | "*";
1060
1037
  /**
1061
- * A relatively strong type for Zip5 or Zip5+4 zip codes
1038
+ * Non-alphabetic characters including whitespace, string numerals, and
1062
1039
  */
1063
- type ZipCode = Zip5 | `${Zip5}-${Zip4}`;
1064
-
1065
- /**
1066
- * If **ALL CAPS** it converts to all lowercase; if not then it does nothing */
1067
- type LowerAllCaps<T extends string> = AllCaps<T> extends true ? Lowercase<T> : T;
1040
+ type NonAlpha = Whitespace | Punctuation | NumericString | Bracket | SpecialCharacters;
1041
+ type Ipv4 = `${number}.${number}.${number}.${number}`;
1068
1042
 
1069
- type Delimiter = "_" | "-" | " ";
1070
- /** convert all delimiters to dashes */
1071
- type DashDelim<T extends string> = T extends `${infer Begin}${" "}${infer Rest}` ? DashDelim<`${Begin}-${Rest}`> : T extends `${infer Begin}${"_"}${infer Rest}` ? DashDelim<`${Begin}-${Rest}`> : T;
1072
1043
  /**
1073
- * Converts a string literal type to a **PascalCase** representation.
1074
- * ```ts
1075
- * // "FooBar"
1076
- * type T = PascalCase<"fooBar">;
1077
- * type T = PascalCase<"foo-bar">;
1078
- * type T = PascalCase<"foo_bar">;
1079
- * type T = PascalCase<"\n foo_bar \t">;
1080
- * ```
1044
+ * Extracts the _required_ keys in the object's type. You also may
1045
+ * optionally filter by the _value_ of the key.
1081
1046
  */
1082
- type PascalCase<S extends string> = string extends S ? string : Trim<DashDelim<LowerAllCaps<S>>> extends `${infer Begin}${Delimiter}${infer Rest}` ? PascalCase<`${Capitalize<Begin>}${Capitalize<Rest>}`> : Capitalize<Trim<LowerAllCaps<S>>>;
1083
-
1084
- type CamelCase<S extends string> = string extends S ? string : Uncapitalize<PascalCase<S>>;
1085
-
1047
+ type RequiredKeys<T extends object, V extends any = any> = {
1048
+ [K in keyof T]-?: {} extends {
1049
+ [P in K]: T[K];
1050
+ } ? never : T[K] extends V ? K : never;
1051
+ }[keyof T];
1086
1052
  /**
1087
- * Capitalize all words in a string
1053
+ * Extracts the intersecting/common keys to two objects
1088
1054
  */
1089
- type CapitalizeWords<S extends string> = S extends `${infer L} ${infer R}` ? `${CapitalizeWords<L>} ${CapitalizeWords<R>}` : S extends `${infer L},${infer R}` ? `${CapitalizeWords<L>},${CapitalizeWords<R>}` : S extends `${infer L}.${infer R}` ? `${CapitalizeWords<L>}.${CapitalizeWords<R>}` : Capitalize<S>;
1090
-
1091
- type DashToSnake<T extends string> = T extends `${infer HEAD}-${infer TAIL}` ? DashToSnake<`${HEAD}_${TAIL}`> : T;
1092
-
1055
+ type IntersectingKeys<T extends Record<string, any> | readonly string[], U extends Record<string, any> | readonly string[]> = {
1056
+ [K in keyof T]: K extends Keys<U> ? K : never;
1057
+ }[keyof T];
1093
1058
  /**
1094
- * Indicates whether `T` has uppercase characters in it.
1095
- * ```ts
1096
- * // true
1097
- * type T = HasUppercase<"Foobar">;
1098
- * // false
1099
- * type T = HasUppercase<"foobar">;
1100
- * // "unknown"
1101
- * type T = HasUppercase<string>;
1102
- * ```
1059
+ * Extracts the _optional_ keys in the object's type. You also may
1060
+ * optionally filter by the _value_ of the key.
1103
1061
  */
1104
- type HasUppercase<T extends string> = string extends T ? "unknown" : T extends `${string}${UpperAlpha}${string}` ? true : false;
1105
-
1106
- type _DU<T extends string> = T extends Lowercase<T> ? T : `-${Lowercase<T>}`;
1062
+ type OptionalKeys<T extends object, V extends any = any> = {
1063
+ [K in keyof T]-?: {} extends {
1064
+ [P in K]: T[K];
1065
+ } ? V extends T[K] ? K : never : never;
1066
+ }[keyof T];
1107
1067
  /**
1108
- * Converts uppercase characters to a dash and then the lowercase equivalent
1068
+ * The _keys_ on a given object `T` which have a literal value of `W`.
1069
+ *
1070
+ * Optionally, you may provide a generic `E` to exclude certain keys in
1071
+ * result set.
1109
1072
  * ```ts
1110
- * // "one-two-three"
1111
- * type T = DashUppercase<"oneTwoThree">;
1073
+ * // "foo"
1074
+ * type Str = KeysWithValue<{ foo: "hi"; bar: 5 }>;
1112
1075
  * ```
1113
- *
1114
- * _Intended to be used as a lower level utility; prefer `Dasherize<T>` for more full-fledged
1115
- * dash solution_.
1116
1076
  */
1117
- type DashUppercase<T extends string> = HasUppercase<T> extends false ? T : T extends `${infer C0}${infer C1}${infer R}` ? `${_DU<C0>}${_DU<C1>}${DashUppercase<R>}` : T extends `${infer C0}${infer R}` ? `${_DU<C0>}${DashUppercase<R>}` : "";
1118
-
1119
- type OneToOne = `1:1`;
1120
- type OneToMany = `1:M`;
1121
- type OneToZero = `1:0`;
1122
- type ZeroToOne = `0:1`;
1123
- type ZeroToMany = `0:M`;
1124
- type ZeroToZero = `0:0`;
1125
- type ManyToMany = "M:M";
1126
- type ManyToOne = "M:1";
1127
- type ManyToZero = "M:0";
1128
- type CardinalityNode = "0" | "1" | "M";
1077
+ type KeysWithValue<W extends any, T extends object> = {
1078
+ [K in keyof T]: T[K] extends W ? Readonly<K> : never;
1079
+ }[keyof T];
1129
1080
  /**
1130
- * Cardinality which expects a singular input and requires
1131
- * 1 or many outputs.
1132
- *
1133
- * Note: choose `CardinalityFilter1` if you want to allow output
1134
- * to have no outputs.
1081
+ * A `PrivateKey` must start with a `_` character and then follow with
1082
+ * an alphabetic character
1135
1083
  */
1136
- type Cardinality1 = OneToOne | OneToMany;
1084
+ type PrivateKey = `_${Alpha}${string}`;
1137
1085
  /**
1138
- * Cardinality which expects a singular input and maps to 0,
1139
- * 1, or many outputs.
1086
+ * Keys on an object which have a `_` character as first part of the
1087
+ * name are considered private and this utility will create a union
1088
+ * of all the keys in this category.
1140
1089
  */
1141
- type CardinalityFilter1 = OneToOne | OneToMany | OneToZero;
1090
+ type PrivateKeys<T extends object> = {
1091
+ [K in keyof T]: K extends `_${string}` ? K : never;
1092
+ }[keyof T];
1142
1093
  /**
1143
- * Cardinality which expects a singular input which is allowed to be
1144
- * _undefined_ or the expected type.
1094
+ * **PublicKeys**
1095
+ *
1096
+ * Builds a union type of all keys which are "public" where a public
1097
+ * key is any key which _does not_ start with the `_` character.
1145
1098
  */
1146
- type Cardinality0 = ZeroToOne | ZeroToMany | OneToOne | OneToMany;
1099
+ type PublicKeys<T extends object> = {
1100
+ [K in keyof T]: K extends `_${string}` ? never : K;
1101
+ }[keyof T];
1102
+ type StringKeys<T extends object> = {
1103
+ [K in keyof T]: K extends string ? Readonly<K> : never;
1104
+ }[keyof T];
1147
1105
  /**
1148
- * Cardinality which expects a singular input -- which is allowed to be
1149
- * _undefined_ -- and maps to 0,
1150
- * 1, or many outputs.
1106
+ * The keys of an object which _are not_ a string type
1151
1107
  */
1152
- type CardinalityFilter0 = ZeroToOne | ZeroToMany | OneToOne | OneToMany | OneToZero | ZeroToZero;
1153
- type CardinalityExplicit = `${number}:${number}`;
1108
+ type NonStringKeys<T extends object> = {
1109
+ [K in keyof T]: K extends string ? never : Readonly<K>;
1110
+ }[keyof T];
1111
+ type NumericKeys<T extends object> = {
1112
+ [K in keyof T]: K extends number ? Readonly<K> : never;
1113
+ }[keyof T];
1114
+ type NonNumericKeys<T extends object> = {
1115
+ [K in keyof T]: K extends number ? never : Readonly<K>;
1116
+ }[keyof T];
1154
1117
  /**
1155
- * Cardinality of any sort between two types
1118
+ * **RequiredProps**
1119
+ *
1120
+ * Reduces an object type to only key/value pairs where the key is required
1156
1121
  */
1157
- type Cardinality = CardinalityFilter0 | CardinalityFilter1 | ManyToMany | ManyToOne | ManyToZero | CardinalityExplicit;
1158
- type CardinalityTuple<T extends Cardinality> = UnionToTuple<T>;
1122
+ type RequiredProps<T extends object> = Pick<T, RequiredKeys<T>>;
1159
1123
  /**
1160
- * The first or _input_ part of the Cardinality relationship
1161
- */
1162
- type CardinalityIn<T extends Cardinality> = T extends `${infer IN}:${string}` ? IN : never;
1163
- /**
1164
- * The second or _output_ part of the Cardinality relationship
1124
+ * **OptionalProps**
1125
+ *
1126
+ * Reduces an object to only key/value pairs where the key is optional
1165
1127
  */
1166
- type CardinalityOut<T extends Cardinality> = T extends `${string}:${infer OUT}` ? OUT : never;
1167
- type CardinalityInput<T, C extends Cardinality> = CardinalityTuple<C>[0] extends 0 ? T | undefined : CardinalityTuple<C>[0] extends 1 ? T : T[];
1168
-
1128
+ type OptionalProps<T extends object> = Pick<T, OptionalKeys<T>>;
1169
1129
  /**
1170
- * Converts a string literal into a _dasherized_ format while ignoring _exterior_ whitespace.
1130
+ * **WithValue**
1171
1131
  *
1132
+ * Reduces an object's type down to only those key/value pairs where the
1133
+ * value is of type `W`.
1172
1134
  * ```ts
1173
- * // "foo-bar"
1174
- * type Dash = Dasherize<"foo_bar">;
1175
- * type Dash = Dasherize<"fooBar">;
1176
- * type Dash = Dasherize<"FooBar">;
1177
- * // "\n foo-bar \t"
1178
- * type Dash = Dasherize<"\n foo bar \t">;
1135
+ * const foo = { a: 1, b: "hi", c: () => "hello" }
1136
+ * // { c: () => "hello" }
1137
+ * type W = WithValue<Function, typeof foo>
1179
1138
  * ```
1180
1139
  */
1181
- type Dasherize<S extends string> = string extends S ? string : DashUppercase<Trim<LowerAllCaps<S>>> extends `${infer Begin}${"_" | " "}${infer Rest}` ? Dasherize<`${Lowercase<Begin>}-${Rest}`> : Lowercase<DashUppercase<Uncapitalize<Trim<LowerAllCaps<S>>>>>;
1182
-
1140
+ type WithValue<W extends any, T extends object, E extends any = undefined> = undefined extends E ? Pick<T, KeysWithValue<W, T>> : Omit<Pick<T, KeysWithValue<W, T>>, KeysWithValue<E, T>>;
1141
+ type DictionaryWithoutValue<TDict extends object, TWithoutValue> = Omit<TDict, KeysWithValue<TWithoutValue, TDict>>;
1183
1142
  /**
1184
- * Returns true or false value based on whether the string literal is capitalized.
1185
- * ```ts
1186
- * // true
1187
- * type T2 = IsCapitalized<"One">;
1188
- * // false
1189
- * type T1 = IsCapitalized<"one">;
1190
- * // "unknown"
1191
- * const a: string = "Hi";
1192
- * type T3 = IsCapitalized<typeof a>;
1193
- * ```
1194
- *
1195
- * Note: _if the value passed in is a "string" then the result will be "unknown"_
1143
+ * Reduces an object to only the key/value pairs where the key is a
1144
+ * string.
1196
1145
  */
1197
- type IsCapitalized<T extends string> = string extends T ? "unknown" : T extends Capitalize<T> ? true : false;
1198
-
1199
- /**
1200
- * **KebabCase<T>** is an _alias_ for **Dasherize<T>**.
1201
- * ```ts
1202
- * // "foo-bar"
1203
- * type Kebab = KebabCase<"foo_bar">;
1204
- * type Kebab = KebabCase<"fooBar">;
1205
- * type Kebab = KebabCase<"FooBar">;
1206
- * // "\n foo-bar \t"
1207
- * type Kebab = KebabCase<"\n foo bar \t">;
1208
- * ``` */
1209
- type KebabCase<T extends string> = Dasherize<T>;
1210
-
1211
- type Consonant = "b" | "c" | "d" | "f" | "g" | "h" | "j" | "k" | "l" | "m" | "n" | "p" | "q" | "r" | "s" | "t" | "v" | "w" | "x" | "z" | "y";
1212
- type Exceptions = "photo => photos" | "piano => pianos" | "halo => halos" | "foot => feet" | "man => men" | "woman => women" | "person => people" | "mouse => mice" | "series => series" | "sheep => sheep" | "money => monies" | "deer => deer";
1213
- type SingularException<T = Exceptions> = T extends `${infer SINGULAR} => ${infer PLURAL}` ? SINGULAR : never;
1214
- type PluralException<T extends SingularException, E extends Exceptions = Exceptions> = E extends `${T} => ${infer PLURAL}` ? PLURAL : never;
1215
- type SingularNoun = "s" | "sh" | "ch" | "x" | "z" | "o";
1216
- type F = "f" | "fe";
1217
- type Y = `${Consonant}y`;
1218
- type RemoveTrailingY<T> = T extends `${infer HEAD}y` ? HEAD : T;
1219
- /** validates that a word ends with a pluralization exception */
1220
- type isException<T extends string> = T extends SingularException ? T : never;
1221
- /** validates that a string literal ends in "is" */
1222
- type EndsIn_IS<T extends string> = T extends `${infer HEAD}is` ? T : never;
1223
- /** validates that a string literal is a singular noun */
1224
- type EndsInSingularNoun<T extends string> = T extends `${infer HEAD}${SingularNoun}` ? T : never;
1225
- /** validates that a string literal ends in "f" or "fe" */
1226
- type EndsIn_F<T extends string> = T extends `${infer HEAD}${F}` ? T : never;
1227
- /** validates that a string literal ends a consonant followed by "y" */
1228
- type EndsIn_Y<T extends string> = T extends `${infer HEAD}${Y}` ? T : never;
1146
+ type WithStringKeys<T extends object> = Omit<T, NonStringKeys<T>>;
1229
1147
  /**
1230
- * strings which end in the letters "is" should have an "es" added to the end
1148
+ * Reduces an object to only the key/value pairs where the key is numeric.
1231
1149
  */
1232
- type PluralizeEndingIn_IS<T extends string> = T extends `${infer HEAD}is` ? `${HEAD}ises` : T;
1150
+ type WithNumericKeys<T extends object> = Omit<T, NonNumericKeys<T>>;
1151
+
1233
1152
  /**
1234
- * singular nouns should have "es" added to the end
1153
+ * **Transformer**
1154
+ *
1155
+ * A function responsible for transforming the _values_ of
1156
+ * dictionary `I` into different _values_ for dictionary `O`.
1157
+ *
1158
+ * This type utility assumes that _keys_ of both dictionaries
1159
+ * are the same.
1235
1160
  */
1236
- type PluralizeEndingSingularNoun<T extends string> = T extends `${infer HEAD}${SingularNoun}` ? `${T}es` : T;
1161
+ type Transformer<I extends object, O extends SameKeys<I>, K extends keyof I = keyof I> = (input: I, key: K) => O[K];
1162
+
1237
1163
  /**
1238
- * strings which end in the letters "f" or "fe" should have "ves" replace the ending
1164
+ * Takes a dictionary of type `I` and converts it to a dictionary of type `O` where
1165
+ * they _keys_ used in both dictionaries are the same.
1166
+ *
1167
+ * The _transform_ function passed in must be able to recieve the full input object
1168
+ * and key, and then return expected value of `O` for the given key.
1239
1169
  */
1240
- type PluralizeEnding_F<T extends string> = T extends `${infer HEAD}${F}` ? `${HEAD}ves` : T;
1170
+ declare function dictionaryTransform<I extends object, O extends SameKeys<I>>(input: I, transform: Transformer<I, O>): O;
1171
+
1172
+ interface Uniqueness<T> {
1173
+ /** boolean flag to indicate whether the property was unique across all records */
1174
+ isUnique: boolean;
1175
+ /** the overall number of records which contained the property */
1176
+ size: number;
1177
+ /** specifies if undefined values were encountered for this property */
1178
+ includedUndefined: boolean;
1179
+ /** the unique values for the property across all records */
1180
+ values: readonly T[];
1181
+ }
1182
+ type DictArrApi<T extends Record<string, Narrowable>, A extends readonly T[]> = {
1183
+ length: number;
1184
+ toLookup<PL extends RequiredKeys<T, string> & keyof T & string>(prop: PL): UniqueForProp<A, PL> extends string ? Record<UniqueForProp<A, PL>, T> : Record<string, T>;
1185
+ sum<PS extends RequiredKeys<T, number> | OptionalKeys<T, number>>(prop: PS): number;
1186
+ count<PC extends OptionalKeys<T>>(prop: PC): number;
1187
+ unique<PU extends Keys<T> & keyof T>(prop: PU): Uniqueness<T[PU]>;
1188
+ };
1241
1189
  /**
1242
- * singular nouns should have "es" added to the end
1190
+ * converts an array of objects to a dictionary with keys formed from a given property
1191
+ * of the object and the value being the object itself.
1243
1192
  */
1244
- type PluralizeEndingIn_Y<T extends string> = T extends `${infer HEAD}${Y}` ? `${RemoveTrailingY<T>}ies` : T;
1245
- type Pluralize<T extends string> = T extends isException<T> ? PluralException<T> : T extends EndsIn_IS<T> ? PluralizeEndingIn_IS<T> : T extends EndsInSingularNoun<T> ? PluralizeEndingSingularNoun<T> : T extends EndsIn_F<T> ? PluralizeEnding_F<T> : T extends EndsIn_Y<T> ? PluralizeEndingIn_Y<T> : `${T}s`;
1193
+ declare const dictArr: <T extends Record<string, Narrowable>>(...dicts: readonly T[]) => DictArrApi<T, readonly T[]>;
1246
1194
 
1247
- /** convert space to dash */
1248
- type SpaceToDash<T extends string> = T extends `${infer Begin}${" "}${infer Rest}` ? SpaceToDash<`${Begin}-${Rest}`> : T;
1249
- /**
1250
- * Converts a string literal type to _snake_case_.
1251
- * ```ts
1252
- * // "foo_bar"
1253
- * type T = SnakeCase<"fooBar">;
1254
- * type T = SnakeCase<"FooBar">;
1255
- * type T = SnakeCase<"foo-bar">;
1256
- * type T = SnakeCase<"\n foo bar \t">;
1257
- * ``` */
1258
- type SnakeCase<S extends string> = string extends S ? string : DashUppercase<Uncapitalize<SpaceToDash<Trim<LowerAllCaps<S>>>>> extends `${infer Begin}${"-"}${infer Rest}` ? SnakeCase<`${Lowercase<Begin>}_${Rest}`> : Lowercase<DashUppercase<Uncapitalize<Trim<LowerAllCaps<S>>>>>;
1195
+ type DictFromKv<T extends readonly {
1196
+ key: string;
1197
+ value: unknown;
1198
+ }[]> = {
1199
+ [R in T[number] as R["key"]]: R["value"];
1200
+ };
1259
1201
 
1260
- type NetworkProtocol = "http" | "https" | "file" | "ws" | "wss";
1261
- /**
1262
- * A literal variant of _string_ which is meant to represent a domain name
1263
- * (e.g., `www.someplace.com`, etc.)
1264
- */
1265
- type DomainName = `${AlphaNumeric}${string}.${AlphaNumeric}${string}` | `${AlphaNumeric}${string}.${AlphaNumeric}${string}.${string}` | `${AlphaNumeric}${string}.${AlphaNumeric}${string}.${string}.${string}`;
1266
- type RelativeUrl = `${VariableName | "/"}`;
1267
1202
  /**
1268
- * A literal variant of _string_ which forces a string to follow conventions
1269
- * for a fully qualified URL like `https://google.com`. It can't ensure the
1270
- * type is fully valid but does help to avoid some typos.
1203
+ * Provides a strongly typed _key_ and _value_ for a dictionary `T`
1204
+ *
1205
+ * ```ts
1206
+ * type Obj = { foo: 1, bar: "hi" };
1207
+ * // ["foo", 1 ]
1208
+ * type Foo = KeyValue<Obj, "foo">;
1209
+ * ```
1271
1210
  */
1272
- type FullyQualifiedUrl = `${NetworkProtocol}://${Ipv4 | DomainName}/${string}`;
1273
- type UrlBuilder = (<P extends NetworkProtocol, D extends DomainName, B extends RelativeUrl>(protocol: P, domain: D, basePath: B) => `${P}://${D}/${B}`) | (<U extends RelativeUrl>(url: U) => U);
1211
+ type KeyValue<T extends object, K extends keyof T> = [K & keyof T, ExpandRecursively<T[K]>];
1274
1212
 
1275
1213
  /**
1276
- * Given a dictionary of key/values, where the value is a function, this
1277
- * type utility will maintain the keys but change the values to whatever
1278
- * the `ReturnType` of the function was.
1214
+ * Type utility which takes an object type and converts to an array of KV objects:
1279
1215
  * ```ts
1280
- * const api = {
1281
- * val: 42,
1282
- * hi: (name: string) => `hi ${name}`,
1283
- * bye: (name: string) => `bye ${name}`
1284
- * };
1285
- * // { hi: string; bye: string }
1286
- * type Test = UnwrapValue<typeof api>
1287
- * // { val: number; foo: string; bar: string }
1288
- * type Test2 = UnwrapValue<typeof api, false>
1216
+ * // [ {key: "id", value: 123 } | {key: "foo", value: "bar" } ][]
1217
+ * type Arr = KvFrom<{ id: 123, foo: "bar" }>;
1289
1218
  * ```
1290
1219
  */
1291
- type DictPartialApplication<T extends Record<string, any>, I extends boolean = true> = SimplifyObject<{
1292
- [K in keyof T]: T[K] extends (...args: any[]) => any ? Record<K, ReturnType<T[K]>> : true extends I ? never : Record<K, T[K]>;
1220
+ type KvFrom<T extends object> = Array<{
1221
+ [K in keyof T]: {
1222
+ key: K;
1223
+ value: T[K];
1224
+ };
1293
1225
  }[keyof T]>;
1294
1226
 
1295
1227
  /**
1296
- * Allow a dictionary have it's value's type changed to `T` while maintaining the keys in
1297
- * the original object `I` so long as the original value for the KV pair extends `V`.
1228
+ * **KvTuple**
1298
1229
  *
1299
- * If `V` is not specified then it defaults to _any_ and therefore all KVs are preserved.
1230
+ * a key/value of type `T` represented as `[key, kv]`
1300
1231
  *
1301
1232
  * ```ts
1302
- * type Obj = { foo: "hello", bar: 42, baz: () => "world" };
1303
- * // { foo: number, bar: number, baz: number };
1304
- * type AllNumbers = DictChangeValue<Obj, number>;
1305
- * // { foo: number }
1306
- * type StringToBool = DictChangeValue<Obj, boolean, string>
1233
+ * type Obj = { foo: 1, bar: "hi" };
1234
+ * // ["foo", { foo: 1 } ]
1235
+ * type Foo = KvTuple<Obj, "foo">;
1307
1236
  * ```
1237
+ *
1238
+ * **Note:** _consider use of `KeyValue<T,K>` as an alternate representation_
1308
1239
  */
1309
- type DictChangeValue<
1310
- /** the object who's value-type we're changing */
1311
- I extends Record<string, any>,
1312
- /** the return type that functions should be modified to have */
1313
- T extends any,
1314
- /**
1315
- *The type we expect in the value; if the value extends type `V` then the value will
1316
- * be converted to type `O`; if not then the KV pair will be discarded
1317
- */
1318
- V extends any = any> = SimplifyObject<{
1319
- [K in keyof I]: I[K] extends V ? Record<K, T> : never;
1320
- }[keyof I]>;
1240
+ type KvTuple<T, K extends keyof T> = [K, Record<K, T[K]>];
1321
1241
 
1322
1242
  /**
1323
- * **DictPrependWithFn**
1243
+ * **entries**
1324
1244
  *
1325
- * Given a strongly typed object `<T>`, this utility will inject a function call with
1326
- * arguments `<A>` and then return what had subsequently been the value of the property.
1245
+ * Provides an _iterable_ over the passed in dictionary object where each iteration
1246
+ * provides a tuple of `[ key, value ]` which preserve type literals.
1327
1247
  *
1328
- * Should you only want to apply this treatment to _some_ of the properties you can
1329
- * pass in a value `<E>` which will ensure that only properties which _extend_ `E` will be
1330
- * modified.
1248
+ * For example:
1249
+ * ```ts
1250
+ * const obj = { foo: 1, bar: "hi" };
1251
+ * // k type is "foo" then "bar"; v type is 1 then "hi"
1252
+ * for (const [k, v] of entries(obj)) { ... }
1253
+ * ```
1331
1254
  */
1332
- type DictPrependWithFn<T extends Record<string, any>, A extends any[], E extends any = any> = SimplifyObject<{
1333
- [K in keyof T]: T[K] extends E ? Record<K, (...args: A) => T[K]> : Record<K, T[K]>;
1334
- }[keyof T]>;
1255
+ declare function entries<N extends Narrowable, T extends Record<string, N>, I extends KeyValue<T, keyof T>>(obj: T): {
1256
+ [Symbol.iterator](): Generator<I, void, unknown>;
1257
+ };
1335
1258
 
1336
1259
  /**
1337
- * **DictReturnValues**
1260
+ * **mapValues**
1338
1261
  *
1339
- * A type utility which receives an object `<T>` and then modifies
1340
- * the return type of any properties which are a function to have this
1341
- * new **ReturnType** `<R>`. Optionally you can specify a particular return type which
1342
- * you are targeting and then
1262
+ * Maps over a dictionary, preserving the keys but allowing the values to be mutated.
1263
+ *
1264
+ * ```ts
1265
+ * const colors = { red: 4, blue: 2, green: 3 };
1266
+ * // { red: 8, blue: 4, green: 6 }
1267
+ * const twoX = mapValues(colors, v => v * 2);
1268
+ * ```
1343
1269
  */
1344
- type DictReturnValues<
1345
- /** the object which we expect to have props with function values */
1346
- T extends Record<string, any>,
1347
- /** the return type that functions should be modified to have */
1348
- R extends any,
1349
- /** optionally this utility can target only functions with a certain existing return value */
1350
- O extends (...args: any[]) => any = (...args: any[]) => any> = SimplifyObject<{
1351
- [K in keyof T]: T[K] extends O ? T[K] extends (...args: infer A) => any ? Record<K, (...args: A) => R> : Record<K, T[K]> : Record<K, T[K]>;
1352
- }[keyof T]>;
1270
+ declare function mapValues<N extends Narrowable, T extends Record<string, N>, V>(obj: T, valueMapper: (k: T[keyof T]) => V): { [K in keyof T]: V; };
1353
1271
 
1354
1272
  /**
1355
- * Expresses whether an option is "opt" (optional) or "req" (required)
1273
+ * converts an array of strings `["a", "b", "c"]` into a more type friendly
1274
+ * dictionary of the type `{ a: true, b: true, c: true }`
1356
1275
  */
1357
- type OptRequired = "opt" | "req";
1276
+ declare function strArrayToDict<T extends readonly string[]>(...strings: T): ExpandRecursively<Record<T[number], true>>;
1358
1277
 
1359
- declare const DEFAULT_ONE_TO_MANY_MAPPING: FinalizedMapConfig<"req", "I -> O[]", "opt">;
1360
- declare const DEFAULT_ONE_TO_ONE_MAPPING: FinalizedMapConfig<"req", "I -> O", "req">;
1361
- declare const DEFAULT_MANY_TO_ONE_MAPPING: FinalizedMapConfig<"req", "I[] -> O", "req">;
1362
- type DefaultOneToManyMapping = typeof DEFAULT_ONE_TO_MANY_MAPPING;
1363
- type DefaultOneToOneMapping = typeof DEFAULT_ONE_TO_ONE_MAPPING;
1364
- type DefaultManyToOneMapping = typeof DEFAULT_MANY_TO_ONE_MAPPING;
1365
1278
  /**
1366
- * **mapTo** _utility_
1367
- *
1368
- * This utility -- by default -- creates a strongly typed 1:M data mapper which maps from one
1369
- * known source `I` to any array of another `O[]`:
1279
+ * Converts a dictionary object into an array of dictionaries with `key` and `value` properties
1370
1280
  * ```ts
1371
- * const mapper = mapTo<I, O>(i => [{
1372
- * foo: i.bar
1373
- * }]);
1281
+ * // [ { key: "id", value: 123 }, { key: "foo", value: "bar" } ]
1282
+ * const arr = dictToKv({ id: 123, foo: "bar" });
1374
1283
  * ```
1375
1284
  */
1376
- declare const mapToFn: ConfiguredMap<DefaultOneToManyMapping>["map"];
1285
+ declare function dictToKv<N extends Narrowable, T extends {
1286
+ [key: string]: N;
1287
+ }, U extends boolean>(obj: T, _makeTuple?: U): U extends true ? UnionToTuple<(Mutable<T> extends infer T_1 extends object ? { [K in keyof T_1]: {
1288
+ key: K;
1289
+ value: Mutable<T>[K];
1290
+ }; } : never)[keyof T], LastInUnion<(Mutable<T> extends infer T_1 extends object ? { [K in keyof T_1]: {
1291
+ key: K;
1292
+ value: Mutable<T>[K];
1293
+ }; } : never)[keyof T]>> : KvFrom<Mutable<T>>;
1294
+
1295
+ type DictArrayFilterCallback<K extends keyof T, T extends object, R extends true | false> = (key: K, value: Pick<T, K>) => R;
1377
1296
  /**
1378
- * Provides a `config` method which allows the relationships between _inputs_
1379
- * and _outputs_ to be configured.
1297
+ * An element in a `DictArray` shaped as a two element tuple: `[key, kv]`.
1380
1298
  */
1381
- declare const mapToDict: MapperApi;
1299
+ type DictArrayKv<K extends keyof T, T> = [K, Pick<T, K>];
1300
+ type DictKvTuple<K extends string> = [K, Record<K, unknown>];
1382
1301
  /**
1383
- * **mapTo** _utility_
1384
- *
1385
- * This utility creates a strongly typed data mapper which maps from one
1386
- * known source `I` to another `O`.
1387
- *
1388
- * Signatures:
1302
+ * A an array of `DictArrayKv` tuples which can be reconstructed
1303
+ * to a strongly typed dictionary object.
1389
1304
  * ```ts
1390
- * const defMap = mapTo<I,O>( ... );
1391
- * const configured = mapTo.config({ output: "req" }).map<I,O>( ... );
1392
- * const one2one = mapTo.oneToOne().map<I,O>( ... );
1393
- * const many2one = mapTo.manyToOne().map<I,O>( ... );
1305
+ * const example: DictArray<{ foo: 1, bar: "hi" }> = [
1306
+ * [ "foo", { foo: 1 }],
1307
+ * [ "bar", { bar: "hi" }]
1308
+ * ]
1394
1309
  * ```
1395
1310
  */
1396
- declare const mapTo: (<I, O>(map: (source: I) => O[]) => Mapper<I, O, FinalizedMapConfig<"req", "I -> O[]", "opt">>) & MapperApi;
1311
+ type DictArray<T> = Array<{
1312
+ [K in keyof T]: DictArrayKv<K, T>;
1313
+ }[keyof T]>;
1397
1314
 
1398
1315
  /**
1399
- * Expresses relationship between inputs/outputs:
1316
+ * Returns the _first_ key in an object.
1317
+ *
1318
+ * **Note:** key order is not guarenteed so typically this is used
1319
+ * for a key/value pair where only one key is expected
1400
1320
  */
1401
- declare enum MapCardinality {
1402
- /** every input results in 0:M outputs */
1403
- OneToMany = "I -> O[]",
1404
- /** every input results in 0:1 outputs */
1405
- OneToOne = "I -> O",
1406
- /** every input is an array of type I and reduced to a single O */
1407
- ManyToOne = "I[] -> O"
1408
- }
1409
- type MapCardinalityIllustrated = EnumValues<MapCardinality>;
1321
+ type FirstKey<T extends object> = UnionToTuple<Keys<T>>[0];
1322
+
1410
1323
  /**
1411
- * The _user_ configuration of a **mapTo** mapper function
1412
- * which will be finalized by merging it with the appropriate
1413
- * default mapping type.
1324
+ * Utility type which operates on a dictionary and provides the **value** of the
1325
+ * `First<T>` key of the dictionary. Because dictionary's don't provide assurances
1326
+ * about key order, this is typically only used in cases where it's known there is
1327
+ * a single key on the object.
1414
1328
  */
1415
- interface MapConfig<IR extends OptRequired | undefined = undefined, D extends MapCardinalityIllustrated | undefined = undefined, OR extends OptRequired | undefined = undefined> {
1416
- input?: IR;
1417
- output?: OR;
1418
- cardinality?: D;
1419
- /**
1420
- * Whether calls to the final `MapFn` will be logged to stderr
1421
- * for debugging purposes. Defaults to false; if you specify
1422
- * a _string_ for a value that will be sent to stderr along
1423
- * with other debugging info.
1424
- */
1425
- debug?: boolean | string;
1426
- }
1329
+ type FirstKeyValue<T extends object> = FirstKey<T> extends keyof T ? T[FirstKey<T>] : never;
1330
+
1427
1331
  /**
1428
- * A finalized configuration of a **mapTo** mapper functions cardinality
1429
- * relationships between _inputs_ and _outputs_.
1332
+ * For a two-dimensional array, returns a _union type_ which combines the first element of the interior
1333
+ * array.
1430
1334
  *
1431
- * Note: _this configuration does _not_ yet include the actual mapping
1432
- * configuration between the input and output._
1335
+ * ```ts
1336
+ * const test = [ ["foo", 1], ["bar", 2] ];
1337
+ * // "foo" | "bar"
1338
+ * type F = FirstOfEach<typeof test>;
1339
+ * ```
1433
1340
  */
1434
- type FinalizedMapConfig<IR extends OptRequired = MapIR<DefaultOneToManyMapping>, D extends MapCardinalityIllustrated = MapCard<DefaultOneToManyMapping>, OR extends OptRequired = MapOR<DefaultOneToManyMapping>> = Required<Omit<MapConfig<IR, D, OR>, "debug">> & {
1435
- finalized: true;
1436
- debug: boolean | string;
1437
- };
1341
+ type FirstOfEach<T extends readonly any[][]> = T[number][0] extends T[number][number] ? T[number][0] : never;
1342
+
1438
1343
  /**
1439
- * User configuration exposed by a config function which specifies the
1440
- * cardinality already (e.g., `oneToMany()`, `manyToOne()`)
1344
+ * Typescript utility which receives `T` as shape which resembles `DictArray<D>`
1345
+ * and if the type `D` can be inferred it is returned.
1346
+ * ```ts
1347
+ * // { foo: 1; bar: "hi" }
1348
+ * type Dict = FromDictArray<[["foo", { foo: 1 }], ["bar", { bar: "hi" }]]>;
1349
+ * ```
1441
1350
  */
1442
- type MapCardinalityConfig<IR extends OptRequired | undefined, OR extends OptRequired | undefined> = {
1443
- /** whether we the input can _optionally_ be an `undefined` value or not */
1444
- input?: IR;
1445
- /** whether we the output can _optionally_ be an `undefined` value or not */
1446
- output?: OR;
1447
- /**
1448
- * Whether calls to the final `MapFn` will be logged to stderr
1449
- * for debugging purposes. Defaults to false; if you set to a string
1450
- * value than this will be echoed out with stderr.
1451
- */
1452
- debug?: boolean | string;
1453
- };
1351
+ type FromDictArray<T extends [string, Record<string, unknown>][]> = ExpandRecursively<UnionToIntersection<T[number][1]>>;
1352
+
1454
1353
  /**
1455
- * **ConfiguredMap**
1354
+ * For a two-dimensional array, returns a _union type_ which combines the first element of the interior
1355
+ * array.
1456
1356
  *
1457
- * A partial application of the mapTo() utility which has expressed the
1458
- * configuration of the _inputs_ and _outputs_ and provides a `.map()`
1459
- * method which allows the user configure the specifics of the mapping.
1357
+ * ```ts
1358
+ * // 1 | 2
1359
+ * type F = SecondOfEach<[ ["foo", 1], ["bar", 2] ]>;
1360
+ * ```
1460
1361
  */
1461
- type ConfiguredMap<C extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = {
1462
- map: <I, O>(map: MapTo<I, O, C>) => Mapper<I, O, C>;
1463
- input: MapIR<C>;
1464
- cardinality: MapCard<C>;
1465
- output: MapOR<C>;
1466
- debug: boolean | string;
1467
- };
1362
+ type SecondOfEach<T extends any[][]> = T[number][1] extends T[number][number] ? T[number][1] : never;
1363
+
1364
+ interface Array$1<T> {
1365
+ filter<U extends T>(pred: (a: T) => a is U): U[];
1366
+ }
1468
1367
  /**
1469
- * Extracts the IR, Cardinality, and OR generics from a FinalizedMapConfig
1368
+ * Accepts a `DictArray` and a callback which receives each key
1369
+ * value pair.
1470
1370
  */
1471
- type DecomposeMapConfig<M extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = M extends MapConfig<infer IR, infer D, infer OR> ? IR extends OptRequired | undefined ? D extends MapCardinalityIllustrated | undefined ? OR extends OptRequired | undefined ? [IR, D, OR] : never : never : never : M extends FinalizedMapConfig<infer IR, infer D, infer OR> ? IR extends OptRequired ? D extends MapCardinalityIllustrated ? OR extends OptRequired ? [IR, D, OR] : never : never : never : never;
1472
- /** extracts IR from a `FinalizedMapConfig` */
1473
- type MapIR<T extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = DecomposeMapConfig<T>[0];
1371
+ declare function filterDictArray<T extends object, C extends DictArrayFilterCallback<keyof T, T, true | false>>(dictArr: DictArray<T>, cb: C): DictArray<Omit<T, "">>;
1372
+
1474
1373
  /**
1475
- * extracts the MapCardinality from a `FinalizedMapConfig`
1374
+ * Build a key-value pair where both _key_ and _value_ are inferred. This
1375
+ * includes ensuring that the _key_ is a type literal not just a "string".
1376
+ *
1377
+ * > note: the value will be inferred but if you need to constrain it
1378
+ * > to a narrower type then both inferences will break and you should
1379
+ * > instead use `KV2` to get this capability.
1476
1380
  */
1477
- type MapCard<T extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = DecomposeMapConfig<T>[1];
1478
- /** extracts OR from a `FinalizedMapConfig` */
1479
- type MapOR<T extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = DecomposeMapConfig<T>[2];
1381
+ declare function kv<K extends string, N extends Narrowable, V extends Record<any, N> | boolean | number | string | null | undefined>(key: K, value: V): ExpandRecursively<Record<K, V>>;
1382
+
1480
1383
  /**
1481
- * Merges the types of a userland configuration with a default configuration
1384
+ * Converts an array of dictionaries with `key` and `value` properties to a singular dictionary.
1385
+ * ```ts
1386
+ * // { id: 123, foo: "bar" }
1387
+ * const arr = kvToDict([{ key: "id", value: 123 }, { key: "foo", value: "bar" }]);
1388
+ * ```
1389
+ *
1390
+ * Note: this is the inverse of `dictToKv()` function
1482
1391
  */
1483
- type AsFinalizedConfig<U extends MapConfig<OptRequired | undefined, MapCardinalityIllustrated | undefined, OptRequired | undefined>, D extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = TypeDefault<U, D> extends FinalizedMapConfig<infer IR, infer C, infer OR> ? FinalizedMapConfig<IR, C, OR> : never;
1484
- type MapperApi = {
1485
- /**
1486
- * Provides opportunity to configure _input_, _output_, and _cardinality_
1487
- * prior to providing a mapping function.
1488
- *
1489
- * Note: _the defaults for configuration are defined by the_ `DEFAULT_ONE_TO_MANY_MAPPING`
1490
- * _constant made available as a symbol from this library._
1491
- */
1492
- config: <C extends MapConfig<OptRequired, //
1493
- MapCardinalityIllustrated, OptRequired>>(config: C) => ConfiguredMap<AsFinalizedConfig<C, //
1494
- DefaultOneToManyMapping>>;
1495
- /**
1496
- * Provides a nice 1:1 ratio between the input and output.
1497
- *
1498
- * By default the input and output are considered to be _required_
1499
- * properties but this can be changed with the options hash provided.
1500
- * ```ts
1501
- * const mapper = mapTo.oneToOne().map(...);
1502
- * // add in ability to filter out some inputs
1503
- * const mapAndFilter = mapTo.oneToOne({ output: "opt" })
1504
- * ```
1505
- */
1506
- oneToOne: <C extends MapCardinalityConfig<OptRequired, OptRequired>>(config?: C) => ConfiguredMap<AsFinalizedConfig<C, //
1507
- DefaultOneToOneMapping>>;
1508
- /**
1509
- * **manyToOne** _mapping_
1510
- *
1511
- * Provides a configuration where multiple inputs `I[]` will be mapped to a
1512
- * single output `O`.
1513
- *
1514
- * Choosing this configuration will, by default, set both input and output
1515
- * to be "required" but you can change this default if you so choose.
1516
- */
1517
- manyToOne: <C extends MapCardinalityConfig<OptRequired | undefined, //
1518
- //
1519
- OptRequired | undefined>>(config?: C) => ConfiguredMap<AsFinalizedConfig<C, //
1520
- DefaultManyToOneMapping>>;
1521
- oneToMany: <C extends MapCardinalityConfig<OptRequired | undefined, //
1522
- //
1523
- OptRequired | undefined>>(config?: C) => ConfiguredMap<AsFinalizedConfig<C, //
1524
- DefaultOneToManyMapping>>;
1525
- };
1526
- type MapInput<I, //
1527
- IR extends OptRequired, C extends MapCardinalityIllustrated> = C extends MapCardinality.OneToMany | "I -> O[]" ? IR extends "opt" ? I | undefined : I : C extends MapCardinality.OneToOne | "I -> O" ? IR extends "opt" ? I | undefined : I : C extends MapCardinality.ManyToOne | "I[] -> O" ? IR extends "opt" ? I[] | undefined : I[] : never;
1528
- type MapOutput<O, //
1529
- OR extends OptRequired, C extends MapCardinalityIllustrated> = C extends MapCardinality.OneToMany | "I -> O[]" ? OR extends "opt" ? O[] : [O, ...O[]] : C extends MapCardinality.OneToOne | "I -> O" ? OR extends "opt" ? O | null : O : C extends MapCardinality.ManyToOne | "I[] -> O" ? OR extends "opt" ? O | null : O : never;
1392
+ declare function kvToDict<K extends string, V extends Narrowable, T extends readonly Readonly<{
1393
+ key: K;
1394
+ value: V;
1395
+ }>[]>(kvArr: T): DictFromKv<T>;
1396
+
1530
1397
  /**
1531
- * **MapTo<I, O>**
1398
+ * Type utility which converts `undefined[]` to `unknown[]`
1399
+ */
1400
+ type UndefinedArrayIsUnknown<T extends any[]> = undefined[] extends T ? unknown[] : T;
1401
+ type AsArray<T, W extends boolean = false> = T extends any[] ? W extends true ? Widen<T> : T : W extends true ? UndefinedArrayIsUnknown<Widen<T>[]> : UndefinedArrayIsUnknown<T[]>;
1402
+ /**
1403
+ * Ensures that any input passed in is passed back as an array:
1532
1404
  *
1533
- * A mapping function between an input type `I` and output type `O`. Defaults to using
1534
- * the _default_ OneToMany mapping config.
1405
+ * - if it was already an array than this just serves as an _identity_ function
1406
+ * - if it was not then it wraps the element into a one element array of the
1407
+ * given type
1535
1408
  *
1536
- * **Note:** this type is designed to guide the userland mapping; refer
1537
- * to `MapFn` if you want the type output by the `mapFn()` utility.
1409
+ * Note: by default the _type_ of values will be intentionally widened so that the value "abc"
1410
+ * is of type `string` not the literal `abc`. If you want to keep literal types then
1411
+ * change the optional _widen_ parameter to _false_.
1538
1412
  */
1539
- type MapTo<I, O, C extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired> = DefaultOneToManyMapping> = MapIR<C> extends "opt" ? (source?: MapInput<I, MapIR<C>, MapCard<C>>) => MapOutput<O, MapOR<C>, MapCard<C>> : (source: MapInput<I, MapIR<C>, MapCard<C>>) => MapOutput<O, MapOR<C>, MapCard<C>>;
1540
- type MapFnOutput<I, O, S, OR extends OptRequired, C extends MapCardinalityIllustrated> = C extends "I -> O[]" | MapCardinality.OneToMany ? S extends I[] ? OR extends "opt" ? O[] : [O, ...O[]] : OR extends "opt" ? O[] | null : O[] : C extends MapCardinality.OneToOne | "I -> O" ? S extends I[] ? OR extends "opt" ? O[] : [O, ...O[]] : OR extends "opt" ? O | null : O : C extends MapCardinality.ManyToOne | "I[] -> O" ? S extends I[][] ? OR extends "opt" ? O[] : [O, ...O[]] : OR extends "opt" ? O | null : O : never;
1541
- type MapFnInput<I, IR extends OptRequired, D extends MapCardinalityIllustrated> = D extends "I -> O[]" | MapCardinality.OneToMany ? IR extends "opt" ? I | I[] | undefined : I | I[] : D extends MapCardinality.OneToOne | "I -> O" ? IR extends "opt" ? I | I[] | undefined : I | I[] : D extends MapCardinality.ManyToOne | "I[] -> O" ? IR extends "opt" ? I[] | I[][] | undefined : I[] | I[][] : never;
1413
+ declare const asArray: <T extends Narrowable, W extends boolean = true>(thing: T, _widen?: W | undefined) => AsArray<T, W>;
1414
+
1542
1415
  /**
1543
- * The mapping function provided by the `mapFn()` utility. This _fn_
1544
- * is intended to be used in two ways:
1545
- *
1546
- * 1. Iterative:
1547
- * ```ts
1548
- * const m = mapTo<I,O>(i => [ ... ]);
1549
- * // maps inputs to outputs
1550
- * const out = inputs.map(m);
1551
- * ```
1552
- * 2. Block:
1553
- * ```ts
1554
- * // maps inputs to outputs (filtering or splitting where appr.)
1555
- * const out2 = m(inputs);
1556
- * ```
1557
- */
1558
- type MapFn<I, O, C extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = MapIR<C> extends "opt" ? <S extends MapFnInput<I, MapIR<C>, MapCard<C>>>(source?: S) => MapFnOutput<I, O, S, MapOR<C>, MapCard<C>> : <S extends MapFnInput<I, MapIR<C>, MapCard<C>>>(source: S) => MapFnOutput<I, O, S, MapOR<C>, MapCard<C>>;
1559
- /**
1560
- * **Mapper**
1561
- *
1562
- * A fully configured _mapper_ stemming from the **mapTo()** utility. It is both a mapping
1563
- * function and a dictionary which describes the mapper's properties.
1416
+ * Groups an array of data based on the value of a property
1417
+ * in the objects within the array.
1564
1418
  * ```ts
1565
- * const m = mapTo.oneToOne().map( ... );
1566
- * const mapped = m(inputs);
1567
- * const mappedOver = inputs.map(m);
1568
- * ```
1419
+ * const data = [ {}, {}, {} ];
1569
1420
  *
1570
- * Note: the root of a `Mapper` is the mapper function but
1571
- * this is combined with a dictionary of settings and types
1572
- * which you can use. For instance, look at the `fnSignature`
1573
- * property to get the _type_ signature of the map function.
1574
- */
1575
- type Mapper<I = unknown, O = unknown, C extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired> = FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = {
1576
- input: MapIR<C>;
1577
- output: MapOR<C>;
1578
- cardinality: MapCard<C>;
1579
- debug: boolean | string;
1580
- inputType: I;
1581
- outputType: O;
1582
- /**
1583
- * Provides the _type_ information for mapper function.
1584
- *
1585
- * Note: _this is just a **type**_ not the actual function which positioned
1586
- * at the root of the Mapper type
1587
- */
1588
- fnSignature: MapFn<I, O, C>;
1589
- } & MapFn<I, O, C>;
1590
- /**
1591
- * **MapInputFrom**
1421
+ * ```
1592
1422
  *
1593
- * Type utility which extracts the `I` type from a fully configured `Mapper`
1423
+ * @ignore not implemented
1594
1424
  */
1595
- type MapInputFrom<T extends Mapper> = T extends Mapper<infer I> ? I : never;
1425
+ declare function groupBy<T extends Record<string, Narrowable>>(_data: Readonly<T[]>): void;
1426
+
1596
1427
  /**
1597
- * **MapOutputFrom**
1598
- *
1599
- * Type utility which extracts the output [`O`] type from a fully configured `Mapper`
1428
+ * The basic shape of a `Converter`
1600
1429
  */
1601
- type MapOutputFrom<T extends Mapper> = T extends Mapper<any, infer O> ? O : never;
1430
+ type ConverterShape<S extends Narrowable, N extends Narrowable, B extends Narrowable, O extends Narrowable> = {
1431
+ string: <T extends string>(v: T) => S;
1432
+ number: <T extends number>(v: T) => N;
1433
+ boolean: <T extends boolean>(v: T) => B;
1434
+ object: <T extends Record<string, any>>(v: T) => O;
1435
+ };
1436
+ type ConverterKeys<S, N, B, O> = UnionToTuple<Keys<DictionaryWithoutValue<{
1437
+ string: S;
1438
+ number: N;
1439
+ boolean: B;
1440
+ object: O;
1441
+ }, undefined>>>;
1442
+ type ConverterInputType<T extends string> = T extends "string" ? string : T extends "number" ? number : T extends "boolean" ? boolean : T extends "object" ? Record<string, any> : unknown;
1443
+ type ConverterInputUnion<TConverted extends readonly any[], TRemaining extends readonly string[]> = [] extends TRemaining ? TConverted : ConverterInputUnion<[
1444
+ ...TConverted,
1445
+ ConverterInputType<First<TRemaining>>
1446
+ ], AfterFirst<TRemaining>>;
1602
1447
  /**
1603
- * **MapCardinalityFrom**
1448
+ * **AvailableConverters**
1604
1449
  *
1605
- * Type utility which extracts _cardinality_ of a `Mapper`'s inputs to outputs
1450
+ * Type utility which will produce the correct union type for a "converter"
1606
1451
  */
1607
- type MapCardinalityFrom<T extends Mapper> = T extends Mapper<any, any, infer C> ? C extends FinalizedMapConfig<OptRequired, infer Cardinality, OptRequired> ? Cardinality : never : never;
1452
+ type AvailableConverters<S, N, B, O> = ConverterKeys<S, N, B, O> extends readonly string[] ? TupleToUnion<ConverterInputUnion<[], ConverterKeys<S, N, B, O>>> : never;
1608
1453
 
1609
1454
  /**
1610
- * Given a dictionary of type `<T>`, this utility function will
1611
- * make the `<M>` generic property _mutable_ and all other _read-only_.
1455
+ * **createConverter**(mapper)
1456
+ *
1457
+ * A runtime utility which allows for the creation of a function which
1458
+ * receives multiple wide types (string, number, boolean, object) and then transform it
1459
+ * based on the "wide type" but while retaining the potentially narrow values passed in.
1460
+ *
1461
+ * The number of wide types which the converter will accept is based on how it configured
1462
+ * as there are discrete functions which must be passed in for handling: strings, numbers,
1463
+ * booleans, and "objects" (aka, Record<string,any>).
1612
1464
  *
1613
1465
  * ```ts
1614
- * // { foo: string, bar?: Readonly<number> }
1615
- * type Example = MutableProps<{
1616
- * foo: Readonly<string>,
1617
- * bar?: number
1618
- * }, "foo">;
1466
+ * // handles strings and numbers
1467
+ * const convert = createConverter({
1468
+ * string: s => `the string was ${s}`,
1469
+ * number: n => `the number was ${n}`,
1470
+ * });
1619
1471
  * ```
1620
1472
  */
1621
- type MutableProps<T extends {}, M extends keyof T & string> = ExpandRecursively<Mutable<Pick<T, M>> & Readonly<Pick<T, Keys<T, M>>>>;
1473
+ declare function createConverter<S extends Narrowable = undefined, N extends Narrowable = undefined, B extends Narrowable = undefined, O extends Narrowable = undefined>(mapper: Partial<ConverterShape<S, N, B, O>>): <T extends AvailableConverters<S, N, B, O>>(input: T) => Widen<T> extends string ? S : Widen<Not<T, string>> extends number ? N : Widen<Not<Not<T, string>, number>> extends boolean ? B : Widen<Not<Not<Not<T, string>, number>, boolean>> extends {} ? O : unknown;
1622
1474
 
1475
+ type ExplicitFunction<P extends any[], R extends any> = (...args: P) => R;
1623
1476
  /**
1624
- * Given a dictionary of type `<T>`, this utility function will
1625
- * make the `<R>` generic property _required_ (use a union to make
1626
- * more than one prop required).
1627
- *
1628
- * ```ts
1629
- * // { foo: string, bar?: number }
1630
- * type Example = RequireProps<{foo?: string, bar?: number}, "foo">;
1631
- * ```
1477
+ * Takes a given function and converts it to an explicit representation
1478
+ * where the generics represent the _parameter_ and _return_ typings.
1632
1479
  */
1633
- type RequireProps<T extends {}, R extends keyof T> = ExpandRecursively<Required<Pick<T, R>> & T>;
1480
+ declare function ExplicitFunction<T extends (...args: any[]) => any>(fn: T): ExplicitFunction<Parameters<T>, ReturnType<T>>;
1634
1481
 
1635
1482
  /**
1636
- * **ToFluent**
1637
- *
1638
- * Converts the typing of a dictionary of functions into the same
1639
- * function signatures but changes the return type to be the Fluent API.
1483
+ * **UniqueDictionary**
1640
1484
  *
1641
- * **Note:** this utility also allows a non-fluent API surface `X` to be included as
1642
- * part of the API surface if this is desired.
1485
+ * A dictionary converted by `arrayToObject()` which expects each key `S` to have a only a
1486
+ * single/unique value.
1643
1487
  */
1644
- type ToFluent<T extends {
1645
- [key: string]: (...args: any[]) => any;
1646
- }, X extends object = {}> = {
1647
- [K in keyof T]: (...args: Parameters<T[K]>) => ToFluent<T, X> & X;
1648
- } & X;
1488
+ type UniqueDictionary<S extends PropertyKey, N extends Narrowable, T extends Record<keyof T, N> & Record<S, any>> = {
1489
+ [V in T as V[S]]: V;
1490
+ };
1649
1491
  /**
1650
- * A _pure_ Fluent API which promotes an API surface where _every_ API endpoint must be a function
1651
- * which returns the same API surface.
1652
- *
1653
- * To provide value, this style of Fluent API will need to perform useful _side effects_ when functions
1654
- * on the API surface are called as this structure does not provide any means to maintain an internal state
1655
- * which can be returned later.
1492
+ * **GeneralDictionary**
1656
1493
  *
1657
- * **Note:** _if you prefer a Fluent API with means to _escape_ with an internally managed state then
1658
- * you should prefer the use of the `FluentApi` type._
1494
+ * A dictionary converted by `arrayToObject()` which expects each key `S` to have an
1495
+ * array of values.
1659
1496
  */
1660
- type PureFluentApi<TApi extends Record<string, (...args: any[]) => PureFluentApi<TApi, any>>, TExclude extends string = ""> = {
1661
- [P in keyof TApi]: (...args: Parameters<TApi[P]>) => PureFluentApi<Omit<TApi, TExclude>>;
1497
+ type GeneralDictionary<S extends PropertyKey, N extends Narrowable, T extends Record<keyof T, N> & Record<S, any>> = {
1498
+ [V in T as V[S]]: V[];
1662
1499
  };
1663
-
1500
+ type ArrayConverter<S extends PropertyKey, U extends boolean> =
1664
1501
  /**
1665
- * A type utility which looks at a chain for functions and reduces the type
1666
- * to the final `ReturnType` of the chain.
1502
+ * An `ArrayConverter` is the partial application of the `arrayToObject()`
1503
+ * utility. At this point, the configuration is setup already and all that's
1504
+ * left is to pass in an array of objects.
1505
+ */
1506
+ <N extends Narrowable, T extends Record<keyof T, N> & Record<S, any>>(arr: readonly T[]) => true extends U ? UniqueDictionary<S, N, T> : GeneralDictionary<S, N, T>;
1507
+ /**
1508
+ * Converts an array of objects into a dictionary by picking a property name contained
1509
+ * by all objects and using that as the key to the dictionary.
1667
1510
  *
1668
1511
  * ```ts
1669
- * // number
1670
- * type T = FinalReturn<() => (foo: string) => (bar: string) => () => number>;
1512
+ * const arr = [
1513
+ * { kind: "color", favorite: "blue", likes: 100 },
1514
+ * { kind: "song", favorite: "some song", likes: 25 }
1515
+ * ];
1516
+ * const dict = arrayToObject("kind")(arr);
1671
1517
  * ```
1518
+ *
1519
+ * This will produce a dictionary with keys of `color` and `song`.
1672
1520
  */
1673
- type FinalReturn<T extends any> = T extends (...args: any[]) => any ? FinalReturn<ReturnType<T>> : T;
1674
-
1675
- /**
1676
- * A function which returns a boolean value
1677
- */
1678
- type LogicFunction<T extends readonly any[]> = (...args: T) => boolean;
1521
+ declare function arrayToObject<S extends PropertyKey, U extends boolean>(prop: S, unique?: U): ArrayConverter<S, true extends U ? true : false>;
1679
1522
 
1680
- type DictFromKv<T extends readonly {
1681
- key: string;
1682
- value: unknown;
1683
- }[]> = {
1684
- [R in T[number] as R["key"]]: R["value"];
1685
- };
1523
+ declare function ifSameType<TValue extends Narrowable, TType extends string | number | boolean | object, IF extends Narrowable, ELSE extends Narrowable>(value: TValue, comparisonType: TType, ifExtends: <T extends TType & TValue>(v: T) => IF, doesNotExtend: (v: Not<TValue, TType>) => ELSE): Widen<TValue> extends Widen<TType> ? IF : ELSE;
1686
1524
 
1525
+ declare function isArray<T>(i: T): IsArray<T>;
1687
1526
  /**
1688
- * Provides a strongly typed _key_ and _value_ for a dictionary `T`
1527
+ * **ifArray**(T, IF, ELSE)
1689
1528
  *
1690
- * ```ts
1691
- * type Obj = { foo: 1, bar: "hi" };
1692
- * // ["foo", 1 ]
1693
- * type Foo = KeyValue<Obj, "foo">;
1694
- * ```
1529
+ * A utility which evaluates a type `T` for whether it is an array and then
1695
1530
  */
1696
- type KeyValue<T extends object, K extends keyof T> = [K & keyof T, ExpandRecursively<T[K]>];
1531
+ declare function ifArray<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(val: T, isAnArray: <N extends T & readonly any[]>(arr: N) => IF, isNotAnArray: <N extends Exclude<T, any[]>>(nonArr: N) => ELSE): IfArray<T, IF, ELSE>;
1532
+ declare function ifArrayPartial<T extends Narrowable>(): <IF extends Narrowable, ELSE extends Narrowable>(isAnArray: <N extends T & readonly any[]>(arr: N) => IF, isNotAnArray: <N_1 extends Exclude<T, any[]>>(nonArr: N_1) => ELSE) => <V extends T>(val: V) => IfArray<V, IF, ELSE>;
1697
1533
 
1698
1534
  /**
1699
- * Type utility which takes an object type and converts to an array of KV objects:
1700
- * ```ts
1701
- * // [ {key: "id", value: 123 } | {key: "foo", value: "bar" } ][]
1702
- * type Arr = KvFrom<{ id: 123, foo: "bar" }>;
1703
- * ```
1535
+ * Runtime and type checks whether a variable is a boolean value.
1704
1536
  */
1705
- type KvFrom<T extends object> = Array<{
1706
- [K in keyof T]: {
1707
- key: K;
1708
- value: T[K];
1709
- };
1710
- }[keyof T]>;
1711
-
1537
+ declare function isBoolean<T extends Narrowable>(i: T): IsBoolean<T>;
1712
1538
  /**
1713
- * **KvTuple**
1714
- *
1715
- * a key/value of type `T` represented as `[key, kv]`
1539
+ * **ifBoolean**
1716
1540
  *
1717
- * ```ts
1718
- * type Obj = { foo: 1, bar: "hi" };
1719
- * // ["foo", { foo: 1 } ]
1720
- * type Foo = KvTuple<Obj, "foo">;
1721
- * ```
1541
+ * Strongly type-aware conditional statement which checks whether a value is
1542
+ * a _boolean_ and returns one of two values (strongly typed) based on the evaluation
1543
+ * of this criteria.
1722
1544
  *
1723
- * **Note:** _consider use of `KeyValue<T,K>` as an alternate representation_
1545
+ * @param val the value being tested
1546
+ * @param ifVal the value (strongly typed) returned if val is _boolean_
1547
+ * @param elseVal the value (strongly typed) returned if val is NOT a _boolean
1724
1548
  */
1725
- type KvTuple<T, K extends keyof T> = [K, Record<K, T[K]>];
1549
+ declare function ifBoolean<T, IF, ELSE>(val: T, ifVal: IF, elseVal: ELSE): IsBoolean<T> extends true ? IF : ELSE;
1726
1550
 
1727
- type DictArrayFilterCallback<K extends keyof T, T extends object, R extends true | false> = (key: K, value: Pick<T, K>) => R;
1551
+ declare function isFalse<T>(i: T): IsFalse<T>;
1728
1552
  /**
1729
- * An element in a `DictArray` shaped as a two element tuple: `[key, kv]`.
1553
+ * **ifTrue**
1554
+ *
1555
+ * Strongly type-aware conditional statement which checks whether a value is
1556
+ * a _true_ and returns one of two values (strongly typed) based on the evaluation
1557
+ * of this criteria.
1558
+ *
1559
+ * @param val the value being tested
1560
+ * @param ifVal the value (strongly typed) returned if val is _true_ value
1561
+ * @param elseVal the value (strongly typed) returned if val is NOT a _true_ value
1562
+ *
1563
+ * Note: at runtime there's no way to distinguish if the value was widely or loosely
1564
+ * typed so unlike the type utility there is no "MAYBE" state but if a wide type if
1565
+ * encountered the _type_ will the union of `IF` and `ELSE`.
1730
1566
  */
1731
- type DictArrayKv<K extends keyof T, T> = [K, Pick<T, K>];
1732
- type DictKvTuple<K extends string> = [K, Record<K, unknown>];
1567
+ declare function ifFalse<T extends boolean, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifVal: IF, elseVal: ELSE): IfFalse<T, IF, ELSE, IF | ELSE>;
1568
+
1569
+ type IsFunction<T> = T extends FunctionType ? true : false;
1570
+ type HybridFunction<TProps extends {}> = (<TArgs extends any[]>(...args: TArgs) => any) & TProps;
1571
+ type SimpleFunction = (...args: any[]) => any;
1572
+ type AnyFunction<TProps extends {} = {}> = SimpleFunction | HybridFunction<TProps>;
1733
1573
  /**
1734
- * A an array of `DictArrayKv` tuples which can be reconstructed
1735
- * to a strongly typed dictionary object.
1574
+ * Checks whether a passed in value is a function and ensures run-time and types
1575
+ * are consistent.
1736
1576
  * ```ts
1737
- * const example: DictArray<{ foo: 1, bar: "hi" }> = [
1738
- * [ "foo", { foo: 1 }],
1739
- * [ "bar", { bar: "hi" }]
1740
- * ]
1577
+ * // true
1578
+ * const yup = isFunction(() => "hello world");
1741
1579
  * ```
1580
+ *
1581
+ * Note: the runtime `typeof [variable]` will correctly say "function" when a function is
1582
+ * encountered but if that function also has object types defined then the type will be a big
1583
+ * and ugly union type. This function will give you a proper boolean value in both cases.
1742
1584
  */
1743
- type DictArray<T> = Array<{
1744
- [K in keyof T]: DictArrayKv<K, T>;
1745
- }[keyof T]>;
1585
+ declare function isFunction<T>(input: T): IsFunction<T>;
1746
1586
 
1587
+ type IsNull<T> = T extends null ? true : false;
1588
+ declare function isNull<T extends Narrowable>(i: T): T extends null ? true : false;
1747
1589
  /**
1748
- * Returns the _first_ key in an object.
1590
+ * **ifNull**
1749
1591
  *
1750
- * **Note:** key order is not guarenteed so typically this is used
1751
- * for a key/value pair where only one key is expected
1592
+ * Strongly type-aware conditional statement which checks whether a value is
1593
+ * Null and returns one of two values (strongly typed) based on the evaluation
1594
+ * of this criteria.
1595
+ *
1596
+ * @param val the value being tested
1597
+ * @param ifVal the value (strongly typed) returned if val is `null`
1598
+ * @param elseVal the value (strongly typed) returned if val is NOT `null`
1752
1599
  */
1753
- type FirstKey<T extends object> = UnionToTuple<Keys<T>>[0];
1600
+ declare function ifNull<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifVal: IF, elseVal: ELSE): IsNull<T> extends true ? IF : ELSE;
1754
1601
 
1602
+ type IsNumber<T> = T extends number ? true : false;
1603
+ declare function isNumber<T>(i: T): T extends number ? true : false;
1755
1604
  /**
1756
- * Utility type which operates on a dictionary and provides the **value** of the
1757
- * `First<T>` key of the dictionary. Because dictionary's don't provide assurances
1758
- * about key order, this is typically only used in cases where it's known there is
1759
- * a single key on the object.
1605
+ * **ifNumber**
1606
+ *
1607
+ * Strongly type-aware conditional statement which checks whether a value is
1608
+ * a _number_ and returns one of two values (strongly typed) based on the evaluation
1609
+ * of this criteria.
1610
+ *
1611
+ * @param val the value being tested
1612
+ * @param ifVal the value (strongly typed) returned if val is number
1613
+ * @param elseVal the value (strongly typed) returned if val is NOT a number
1760
1614
  */
1761
- type FirstKeyValue<T extends object> = FirstKey<T> extends keyof T ? T[FirstKey<T>] : never;
1615
+ declare function ifNumber<T, IF, ELSE>(val: T, ifVal: IF, elseVal: ELSE): IsNumber<T> extends true ? IF : ELSE;
1762
1616
 
1617
+ type ObjectType = Not<Record<string, Narrowable>, FunctionType>;
1763
1618
  /**
1764
- * For a two-dimensional array, returns a _union type_ which combines the first element of the interior
1765
- * array.
1766
- *
1767
- * ```ts
1768
- * const test = [ ["foo", 1], ["bar", 2] ];
1769
- * // "foo" | "bar"
1770
- * type F = FirstOfEach<typeof test>;
1771
- * ```
1619
+ * Detects whether the passed in `v` is of type "object" where an object
1620
+ * is defined to be a string keyed dictionary style object. This means that
1621
+ * arrays are excluded, as well as functions which also have properties hanging
1622
+ * off of them.
1772
1623
  */
1773
- type FirstOfEach<T extends readonly any[][]> = T[number][0] extends T[number][number] ? T[number][0] : never;
1624
+ declare function isObject<T extends Narrowable>(i: T): IsObject<T>;
1625
+ declare function ifObject<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifObj: IF, notObj: ELSE): IfObject<T, IF, ELSE>;
1774
1626
 
1775
1627
  /**
1776
- * Typescript utility which receives `T` as shape which resembles `DictArray<D>`
1777
- * and if the type `D` can be inferred it is returned.
1778
- * ```ts
1779
- * // { foo: 1; bar: "hi" }
1780
- * type Dict = FromDictArray<[["foo", { foo: 1 }], ["bar", { bar: "hi" }]]>;
1781
- * ```
1628
+ * **IsString**
1629
+ *
1630
+ * Type utility which returns true/false based on whether `T` is a
1631
+ * string (wide or narrow).
1782
1632
  */
1783
- type FromDictArray<T extends [string, Record<string, unknown>][]> = ExpandRecursively<UnionToIntersection<T[number][1]>>;
1784
-
1633
+ type IsString<T> = T extends string ? true : false;
1785
1634
  /**
1786
- * For a two-dimensional array, returns a _union type_ which combines the first element of the interior
1787
- * array.
1635
+ * **IfString**
1788
1636
  *
1789
- * ```ts
1790
- * // 1 | 2
1791
- * type F = SecondOfEach<[ ["foo", 1], ["bar", 2] ]>;
1792
- * ```
1637
+ * Type utility which determines if `T` is a _string_ (wide or narrow) and
1638
+ * returns `IF` type if it is, otherwise returns the type `ELSE`.
1793
1639
  */
1794
- type SecondOfEach<T extends any[][]> = T[number][1] extends T[number][number] ? T[number][1] : never;
1640
+ type IfString<T extends Narrowable, //
1641
+ IF extends Narrowable, ELSE extends Narrowable> = IsString<T> extends true ? IF : IsString<T> extends false ? ELSE : IF | ELSE;
1795
1642
 
1796
- declare function createFnWithProps<F extends Function, P extends {}>(fn: F, props: P): F & P;
1797
1643
  /**
1798
- * Adds a dictionary of key/value pairs to a function.
1644
+ * **isString**
1645
+ *
1646
+ * Returns true or false on whether the passed in parameter is a
1647
+ * string (either a wide string or a string literal).
1648
+ *
1649
+ * The boolean return is traceable by the type system as well as the
1650
+ * runtime system.
1799
1651
  */
1800
- declare function fnWithProps<A extends any[], R extends any, P extends {}>(fn: ((...args: A) => R), props: P): ((...args: A) => R) & P;
1652
+ declare function isString<T>(i: T): IsString<T>;
1801
1653
  /**
1802
- * Adds read-only (and narrowly typed) key/value pairs to a function
1654
+ * **ifString**
1655
+ *
1656
+ * Strongly type-aware conditional statement which checks whether a value is
1657
+ * a _string_ and returns one of two values (strongly typed) based on the evaluation
1658
+ * of this criteria.
1659
+ *
1660
+ * @param val the value being tested for being a string
1661
+ * @param ifVal the value (strongly typed) returned if val is _string_
1662
+ * @param elseVal the value (strongly typed) returned if val is NOT a _string
1803
1663
  */
1804
- declare function readonlyFnWithProps<A extends any[], R extends any, N extends Narrowable, P extends Record<keyof P, N>>(fn: ((...args: A) => R), props: P): ((...args: A) => R) & Readonly<P>;
1664
+ declare function ifString<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifVal: <E extends string>(t: E & T) => IF, elseVal: ELSE): IfString<T, IF, ELSE>;
1665
+
1666
+ declare function isSymbol<T>(i: T): T extends symbol ? true : false;
1805
1667
 
1806
1668
  /**
1807
- * Provides the _keys_ of an object with the `keyof T` made explicit.
1669
+ * Run-time and type checking of whether a variable is `true`.
1808
1670
  */
1809
- declare function keys<T extends {}, W extends readonly string[]>(obj: T, ...without: W): Length<W> extends 0 ? (keyof T)[] : Exclude<keyof T, Keys<W, undefined>>[];
1810
-
1671
+ declare function isTrue<T extends Narrowable>(i: T): IsTrue<T>;
1811
1672
  /**
1812
- * **ruleSet**
1673
+ * **ifTrue**
1813
1674
  *
1814
- * Defines a ruleset composed of _dynamic_ and _static_ boolean operators.
1675
+ * Strongly type-aware conditional statement which checks whether a value is
1676
+ * _true_.
1815
1677
  *
1816
- * - the first function call defines _dynamic_ props (_optional_)
1817
- * - the second function call defines static values
1678
+ * @param val the value being tested
1679
+ * @param ifVal the value (strongly typed) returned if val is _true_ value
1680
+ * @param elseVal the value (strongly typed) returned if val is NOT a _true_ value
1818
1681
  *
1819
- * ```ts
1820
- * const rs = ruleSet(
1821
- * r => r.state()( { maybe: r => r.extends({ foo: 1 }) })
1822
- * )(
1823
- * { color: true, age: false }
1824
- * );
1825
- * ```
1682
+ * Note: at runtime there's no way to distinguish if the value was widely or loosely
1683
+ * typed so unlike the type utility there is no "MAYBE" state but if a wide type if
1684
+ * encountered the _type_ will the union of `IF` and `ELSE`.
1826
1685
  */
1827
- declare function ruleSet<N extends Narrowable, TState extends Record<keyof TState, N>>(defn?: TState): TState | undefined;
1828
-
1829
- declare const api: <N extends Narrowable, TPrivate extends Readonly<Record<any, N>>>(priv: TPrivate) => <TPublic extends object>(pub: TPublic) => () => TPublic;
1686
+ declare function ifTrue<T extends boolean, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifVal: IF, elseVal: ELSE): IfTrue<T, IF, ELSE, IF | ELSE>;
1830
1687
 
1688
+ declare function isUndefined<T extends Narrowable>(i: T): undefined extends T ? true : false;
1831
1689
  /**
1832
- * Groups a number of "logic functions" together by combining their results using
1833
- * the logical **AND** operator.
1690
+ * **ifUndefined**
1834
1691
  *
1835
- * **Note:** a "logic function" is any function which returns a boolean
1836
- */
1837
- declare const and: <T extends any[]>(...ops: readonly LogicFunction<T>[]) => LogicFunction<T>;
1838
-
1839
- declare function or<O extends readonly boolean[]>(...conditions: O): Or<O>;
1840
-
1841
- /**
1842
- * Groups a number of "logic functions" together by combining their results using
1843
- * the logical **NOT** operator.
1692
+ * Strongly type-aware conditional statement which checks whether a value is
1693
+ * _undefined_ and returns one of two values (strongly typed) based on the evaluation
1694
+ * of this criteria.
1844
1695
  *
1845
- * **Note:** a "logic function" is any function which returns a boolean
1696
+ * @param val the value being tested
1697
+ * @param ifVal the value (strongly typed) returned if val is `undefined`
1698
+ * @param elseVal the value (strongly typed) returned if val is NOT `undefined`
1846
1699
  */
1847
- declare const not: <T extends any[]>(op: LogicFunction<T>) => LogicFunction<T>;
1700
+ declare function ifUndefined<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifVal: IF, elseVal: ELSE): IsUndefined<T> extends true ? IF : ELSE;
1701
+ declare function ifDefined<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifVal: <V extends Exclude<T, undefined>>(v: V) => IF, elseVal: ELSE): IsUndefined<T> extends true ? IF : ELSE;
1848
1702
 
1849
- type FilterStarts = {
1850
- /** one or more string which the value is allowed to start with */
1851
- startsWith: string | string[];
1852
- };
1853
- type FilterIs = {
1854
- /** whether a string _**is**_ of a particular value */
1855
- is: string | string[];
1856
- };
1857
- type FilterEnds = {
1858
- endsWith: string | string[];
1859
- };
1860
- type FilterContains = {
1861
- /** whether any of the strings specified are _contained_ in the value */
1862
- contains: string | string[];
1863
- };
1864
- type FilterEquals = {
1865
- /** one or more values which _equal_ the value passed in */
1866
- equals: number | number[];
1867
- };
1868
- type FilterNotEqual = {
1869
- /** one or more values which ALL _do not equal_ the value passed in */
1870
- notEqual: number | number[];
1871
- };
1872
- type FilterGreaterThan = {
1873
- /** the incoming value is greater than this value */
1874
- greaterThan: number;
1875
- };
1876
- type FilterLessThan = {
1877
- /** the incoming value is less than this value */
1878
- lessThan: number;
1879
- };
1880
- type StringFilter = FilterIs | FilterStarts | FilterEnds | FilterContains | (FilterStarts & FilterEnds) | (FilterStarts & FilterContains) | (FilterEnds & FilterContains) | (FilterStarts & FilterEnds & FilterContains);
1881
- type NumericFilter = FilterEquals | FilterNotEqual | FilterGreaterThan | FilterLessThan | (FilterEquals & FilterNotEqual) | (FilterEquals & FilterGreaterThan) | (FilterEquals & FilterLessThan) | (FilterNotEqual & FilterGreaterThan) | (FilterNotEqual & FilterLessThan) | (FilterGreaterThan & FilterLessThan) | (FilterEquals & FilterGreaterThan & FilterLessThan) | (FilterNotEqual & FilterGreaterThan & FilterLessThan) | (FilterEquals & FilterNotEqual & FilterGreaterThan & FilterLessThan);
1882
- type FilterDefn = StringFilter | NumericFilter;
1883
- type NotFilter = {
1703
+ interface Box<T> {
1704
+ __kind: "box";
1705
+ value: T;
1884
1706
  /**
1885
- * **not**
1707
+ * Unbox the boxed value in the narrowest possible type.
1886
1708
  *
1887
- * If you want to build a filter who's conditions being met results in _filtering_
1888
- * the value rather than accepting it then choose this.
1709
+ * **note:** if the boxed value is a function with parameters you
1710
+ * can pass the parameters directly into the `b.unbox(params)` call.
1889
1711
  */
1890
- not: FilterDefn;
1891
- };
1892
- declare function isNotFilter(f: FilterDefn | NotFilter): f is NotFilter;
1893
- type UnwrapNot<T extends FilterDefn | NotFilter> = T extends NotFilter ? T["not"] extends StringFilter ? StringFilter : NumericFilter : T;
1894
- declare function isNumericFilter(filter: FilterDefn): filter is NumericFilter;
1895
- type UndefinedValue<U extends boolean> = true extends U ? "undefined treated as 'true'" : U extends "no-impact" ? "undefined treated in no-impact fashion" : "undefined treated as 'false'";
1896
- type UndefinedTreatment = "undefined treated as 'true'" | "undefined treated as 'false'";
1897
- type LogicalCombinator = "AND" | "OR";
1712
+ unbox: HasParameters<Box<T>["value"]> extends true ? Box<T>["value"] extends AnyFunction ? Box<T>["value"] extends (...args: infer A) => infer R ? <N extends A>(...args: N) => R : () => ReturnType<T> : () => T : () => T;
1713
+ }
1714
+ type BoxValue<T extends Box<any>> = T extends Box<infer V> ? V : never;
1715
+ type BoxedFnParams<T extends Box<any>> = T extends Box<infer V> ? V extends (...args: infer A) => any ? A : [] : [];
1716
+ type BoxedReturn<T extends Box<any>> = T extends Box<infer V> ? V extends Function ? ReturnType<T["value"]> : T["value"] : never;
1717
+ type NarrowBox<T> = <N extends BoxedFnParams<Box<T>> | First<BoxedFnParams<Box<T>>>>() => N extends BoxedFnParams<Box<T>> ? T extends (...args: any[]) => any ? (...args: N) => Box<T>["unbox"] : never : (first: N, ...rest: AfterFirst<BoxedFnParams<Box<T>>>) => BoxedReturn<Box<T>>;
1898
1718
  /**
1899
- * **FilterFn**
1900
- *
1901
- * A filter function derived from the `filter()` configurator. This function is intended to provide a type-strong _filter_ function which can be used like so:
1902
- * be used like:
1903
- * ```ts
1904
- * const onlyPrivate = filter({ startsWith: "_" });
1905
- * const privateFiles = files.filter(onlyPrivate);
1906
- * ```
1719
+ * Allows a value with an inner-type to be boxed into a dictionary
1720
+ * so that this type inference is preserved with the help of
1721
+ * [instantiation expressions](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7-beta/#instantiation-expressions).
1907
1722
  *
1723
+ * NOTE: this feature is immature at best right now
1908
1724
  */
1909
- type FilterFn<T extends StringFilter | NumericFilter> = T extends StringFilter ? <V extends string | undefined>(input: V) => boolean : <V extends number | undefined>(input: V) => boolean;
1725
+ declare function box<T extends Narrowable>(value: T): Box<T>;
1726
+ declare function isBox(thing: Narrowable): thing is Box<any>;
1910
1727
  /**
1911
- * Defines a logical function for each condition type
1728
+ * **boxDictionaryValues**(dict)
1729
+ *
1730
+ * Runtime utility which boxes each value in a dictionary
1912
1731
  */
1913
- type ConditionFilter<T extends StringFilter | NumericFilter> = T extends StringFilter ? (input: string) => boolean : (input: number) => boolean;
1732
+ declare function boxDictionaryValues<T extends {}>(dict: T): { [K in keyof T]: Box<T[K]>; };
1733
+ type Unbox<T> = T extends Box<infer U> ? U : T;
1914
1734
  /**
1915
- * **filter**
1916
- *
1917
- * A higher order helper utility which builds a boolean _filter_ function based on a simple
1918
- * configuration object. Support either _string_ or _numeric_ filters.
1919
- *
1920
- * ```ts
1921
- * const str = filter({startsWith: ["_", "."], endsWith: ".md"});
1922
- * const num = filter({ greaterThan: 55, notEqual: [66, 77]});
1923
- * ```
1924
- *
1925
- * All conditions (e.g., `startsWith`, `contains`, `notEqual`, etc.) that a particular filter
1926
- * is defined as having -- if there is more than one -- will be logically combined using AND
1927
- * unless specified otherwise in the third parameter.
1735
+ * **unbox**(maybeBox)
1928
1736
  *
1929
- * How a value of _undefined_ will be treated is stated in the second parameter but defaults
1930
- * to "no-impact" which means it's `false` when the logicCombinator is OR but defaults
1931
- * to `true` when the logicCombinator is AND.
1737
+ * Unboxes a value if it was a box; otherwise it leaves _as is_.
1932
1738
  */
1933
- declare const filter: <F extends FilterDefn | NotFilter, U extends boolean | "no-impact", C extends LogicalCombinator>(config: F, logicCombinator?: C, ifUndefined?: U) => FilterFn<UnwrapNot<F>>;
1739
+ declare function unbox<T>(val: T): Unbox<T>;
1934
1740
 
1935
1741
  /**
1936
- * Passing in an array of strings, you are passed back a dictionary with
1937
- * all the keys being the strings and values set to `true`.
1938
- * ```ts
1939
- * // { bar: true, bar: true } as const;
1940
- * const d - dictArr(arr);
1742
+ * Build a _type_ from two run-time dictionaries.
1941
1743
  *
1942
- * const fooBar = arrayToKeyLookup("foo", "bar");
1943
- * ```
1744
+ * 1. The _first_ -- which is optional -- is interpreted as a _literal_ type definition
1745
+ * 2. The _second_ dictionary is interpreted as a "wide" definition of prop types
1944
1746
  */
1945
- declare function arrayToKeyLookup<T extends readonly string[]>(...keys: T): Record<T[number], true>;
1946
-
1947
- interface DefinePropertiesApi<T extends {}> {
1948
- /**
1949
- * Makes a property on the object **readonly** on the Javascript runtime
1950
- */
1951
- ro<K extends keyof T>(prop: K, errorMsg?: (p: K, v: any) => string): Omit<T, K> & Record<K, Readonly<T[K]>>;
1952
- /**
1953
- * Makes a property on the object **read/writeable** on the Javascript runtime;
1954
- * this is the default so only use this where it is needed.
1955
- */
1956
- rw<K extends keyof T>(prop: K): Omit<T, K> & Record<K, Readonly<T[K]>>;
1957
- }
1958
- declare function defineProperties<T extends {}>(obj: T): DefinePropertiesApi<T>;
1747
+ declare function defineType<N extends Narrowable, TLiteral extends Record<string, N>>(literal?: TLiteral): <TWide extends object>(wide?: TWide) => ExpandRecursively<TWide & TLiteral>;
1959
1748
 
1960
1749
  /**
1961
- * Takes a dictionary of type `I` and converts it to a dictionary of type `O` where
1962
- * they _keys_ used in both dictionaries are the same.
1963
- *
1964
- * The _transform_ function passed in must be able to recieve the full input object
1965
- * and key, and then return expected value of `O` for the given key.
1750
+ * An identity function for any type, with the goal of preserving literal type information
1751
+ * whereever possible.
1966
1752
  */
1967
- declare function dictionaryTransform<I extends object, O extends SameKeys<I>>(input: I, transform: Transformer<I, O>): O;
1753
+ declare const identity: <N extends Narrowable, T extends string | number | boolean | symbol | Record<any, N> | null | undefined>(v: T) => T;
1968
1754
 
1969
- interface Uniqueness<T> {
1970
- /** boolean flag to indicate whether the property was unique across all records */
1971
- isUnique: boolean;
1972
- /** the overall number of records which contained the property */
1973
- size: number;
1974
- /** specifies if undefined values were encountered for this property */
1975
- includedUndefined: boolean;
1976
- /** the unique values for the property across all records */
1977
- values: readonly T[];
1978
- }
1979
- type DictArrApi<T extends Record<string, Narrowable>, A extends readonly T[]> = {
1980
- length: number;
1981
- toLookup<PL extends RequiredKeys<T, string> & keyof T & string>(prop: PL): UniqueForProp<A, PL> extends string ? Record<UniqueForProp<A, PL>, T> : Record<string, T>;
1982
- sum<PS extends RequiredKeys<T, number> | OptionalKeys<T, number>>(prop: PS): number;
1983
- count<PC extends OptionalKeys<T>>(prop: PC): number;
1984
- unique<PU extends Keys<T> & keyof T>(prop: PU): Uniqueness<T[PU]>;
1755
+ /**
1756
+ * Takes an object as input --which has an `id` property and returns it as the same
1757
+ * run-time content but with the _type_ of the `id` property being forced to a literal type
1758
+ */
1759
+ declare function idLiteral<T extends {
1760
+ id: I;
1761
+ }, I extends PropertyKey>(o: T): T & {
1762
+ id: T["id"];
1985
1763
  };
1986
1764
  /**
1987
- * converts an array of objects to a dictionary with keys formed from a given property
1988
- * of the object and the value being the object itself.
1765
+ * Takes an object as input --which has an `name` property and returns it as the same
1766
+ * run-time content but with the _type_ of the `name` property being forced to a literal type
1989
1767
  */
1990
- declare const dictArr: <T extends Record<string, Narrowable>>(...dicts: readonly T[]) => DictArrApi<T, readonly T[]>;
1991
-
1768
+ declare function nameLiteral<T extends {
1769
+ name: I;
1770
+ }, I extends PropertyKey>(o: T): T & {
1771
+ name: T["name"];
1772
+ };
1992
1773
  /**
1993
- * **entries**
1774
+ * Takes an object as input --which has an `kind` property and returns it as the same
1775
+ * run-time content but with the _type_ of the `kind` property being forced to a literal type
1776
+ */
1777
+ declare function kindLiteral<T extends {
1778
+ kind: I;
1779
+ }, I extends PropertyKey>(o: T): T & {
1780
+ kind: T["kind"];
1781
+ };
1782
+ declare function idTypeGuard<T extends {
1783
+ id: I;
1784
+ }, I extends PropertyKey>(_o: T): _o is T & {
1785
+ id: I;
1786
+ };
1787
+ /**
1788
+ * Takes an object as input and infers the narrow literal types of the property
1789
+ * values on the object.
1994
1790
  *
1995
- * Provides an _iterable_ over the passed in dictionary object where each iteration
1996
- * provides a tuple of `[ key, value ]` which preserve type literals.
1791
+ * > Note: this addresses this [a known TS gap](https://github.com/microsoft/TypeScript/issues/30680).
1792
+ * > Hopefully at some point this will be addressed in the language.
1793
+ */
1794
+ declare function literal<N extends Narrowable, T extends Record<keyof T, N>>(obj: T): T;
1795
+
1796
+ /**
1797
+ * **StripEnding**`<T, U>`
1997
1798
  *
1998
- * For example:
1799
+ * Will strip off of `T` the ending defined by `U` when
1800
+ * both are string literals.
1999
1801
  * ```ts
2000
- * const obj = { foo: 1, bar: "hi" };
2001
- * // k type is "foo" then "bar"; v type is 1 then "hi"
2002
- * for (const [k, v] of entries(obj)) { ... }
1802
+ * type T = "Hello World";
1803
+ * type U = " World";
1804
+ * // "Hello"
1805
+ * type R = StripEnding<T,U>;
2003
1806
  * ```
2004
1807
  */
2005
- declare function entries<N extends Narrowable, T extends Record<string, N>, I extends KeyValue<T, keyof T>>(obj: T): {
2006
- [Symbol.iterator](): Generator<I, void, unknown>;
2007
- };
1808
+ type StripTrailing<T extends string, U extends string> = IfLiteral<T, string extends U ? never : T extends `${infer Before}${U}` ? Before : T, string>;
2008
1809
 
2009
1810
  /**
2010
- * **mapValues**
1811
+ * **stripTrailing**(content, strip)
2011
1812
  *
2012
- * Maps over a dictionary, preserving the keys but allowing the values to be mutated.
1813
+ * Runtime utility which ensures that last part of a string has substring
1814
+ * removed if it exists and that strong typing is preserved.
1815
+ */
1816
+ declare function stripTrailing<T extends string, U extends string>(content: T, strip: U): StripTrailing<T, U>;
1817
+
1818
+ /**
1819
+ * **EnsureTrailing**`<T, U>`
1820
+ *
1821
+ * Will ensure that `T` ends with the substring `U` when
1822
+ * both are string literals.
2013
1823
  *
2014
1824
  * ```ts
2015
- * const colors = { red: 4, blue: 2, green: 3 };
2016
- * // { red: 8, blue: 4, green: 6 }
2017
- * const twoX = mapValues(colors, v => v * 2);
1825
+ * type T = "Hello";
1826
+ * type U = " World";
1827
+ * // "Hello World"
1828
+ * type R = EnsureTrailing<T,U>;
2018
1829
  * ```
2019
1830
  */
2020
- declare function mapValues<N extends Narrowable, T extends Record<string, N>, V>(obj: T, valueMapper: (k: T[keyof T]) => V): { [K in keyof T]: V; };
1831
+ type EnsureTrailing<T extends string, U extends string> = IfLiteral<T, string extends U ? never : T extends `${string}${U}` ? T : `${T}${U}`, string>;
2021
1832
 
2022
1833
  /**
2023
- * converts an array of strings `["a", "b", "c"]` into a more type friendly
2024
- * dictionary of the type `{ a: true, b: true, c: true }`
1834
+ * **ensureTrailing**(content, strip)
1835
+ *
1836
+ * Runtime utility which ensures that last part of a string -- `content` -- has the
1837
+ * substring `ensure` at the end and adds it if not present.
2025
1838
  */
2026
- declare function strArrayToDict<T extends readonly string[]>(...strings: T): ExpandRecursively<Record<T[number], true>>;
1839
+ declare function ensureTrailing<T extends string, U extends string>(content: T, ensure: U): EnsureTrailing<T, U>;
2027
1840
 
2028
1841
  /**
2029
- * Converts a dictionary object into an array of dictionaries with `key` and `value` properties
1842
+ * Indicates whether `T` has _all_ uppercase characters in it.
2030
1843
  * ```ts
2031
- * // [ { key: "id", value: 123 }, { key: "foo", value: "bar" } ]
2032
- * const arr = dictToKv({ id: 123, foo: "bar" });
1844
+ * // true
1845
+ * type T = AllCaps<"FOOBAR">;
1846
+ * // false
1847
+ * type T = AllCaps<"FooBar">;
1848
+ * // "unknown"
1849
+ * type T = AllCaps<string>;
2033
1850
  * ```
2034
1851
  */
2035
- declare function dictToKv<N extends Narrowable, T extends {
2036
- [key: string]: N;
2037
- }, U extends boolean>(obj: T, _makeTuple?: U): U extends true ? UnionToTuple<(Mutable<T> extends infer T_1 extends object ? { [K in keyof T_1]: {
2038
- key: K;
2039
- value: Mutable<T>[K];
2040
- }; } : never)[keyof T], LastInUnion<(Mutable<T> extends infer T_1 extends object ? { [K in keyof T_1]: {
2041
- key: K;
2042
- value: Mutable<T>[K];
2043
- }; } : never)[keyof T]>> : KvFrom<Mutable<T>>;
1852
+ type AllCaps<T extends string> = string extends T ? "unknown" : T extends Uppercase<T> ? true : false;
2044
1853
 
2045
- interface Array$1<T> {
2046
- filter<U extends T>(pred: (a: T) => a is U): U[];
2047
- }
2048
1854
  /**
2049
- * Accepts a `DictArray` and a callback which receives each key
2050
- * value pair.
1855
+ * **Break<T,D>**
1856
+ *
1857
+ * Takes a string `T`, and splits it into a tuple of the form `[F, R]`.
1858
+ * ```ts
1859
+ * // ["the", " long and winding road"]
1860
+ * type T1 = Break<"the long and winding road", " ">;
1861
+ * // ["there", " I was, there I was"]
1862
+ * type T2 = Break<"there I was, there I was", " ">;
1863
+ * ```
2051
1864
  */
2052
- declare function filterDictArray<T extends object, C extends DictArrayFilterCallback<keyof T, T, true | false>>(dictArr: DictArray<T>, cb: C): DictArray<Omit<T, "">>;
1865
+ type Break<T extends string, D extends string> = (string extends T ? [string, string] : (T extends `${infer F}${D}${infer _R}` ? (F extends `${infer _X}${D}${infer _Y}` ? never : (T extends `${F}${infer R}` ? [F, R] : never)) : [T, ""]));
2053
1866
 
2054
1867
  /**
2055
- * Build a key-value pair where both _key_ and _value_ are inferred. This
2056
- * includes ensuring that the _key_ is a type literal not just a "string".
2057
- *
2058
- * > note: the value will be inferred but if you need to constrain it
2059
- * > to a narrower type then both inferences will break and you should
2060
- * > instead use `KV2` to get this capability.
1868
+ * Concatenates two arrays (of literals).
1869
+ * ```ts
1870
+ * // [ "foo", "bar", "baz" ]
1871
+ * type T = ArrConcat<["foo"], ["bar", "baz"]>;
1872
+ * ```
2061
1873
  */
2062
- declare function kv<K extends string, N extends Narrowable, V extends Record<any, N> | boolean | number | string | null | undefined>(key: K, value: V): ExpandRecursively<Record<K, V>>;
1874
+ type ArrConcat<A extends any[], B extends any[]> = [...A, ...B];
2063
1875
 
2064
1876
  /**
2065
- * Converts an array of dictionaries with `key` and `value` properties to a singular dictionary.
1877
+ * Type utility which takes a string `S` and replaces the substring `W` with `P`.
2066
1878
  * ```ts
2067
- * // { id: 123, foo: "bar" }
2068
- * const arr = kvToDict([{ key: "id", value: 123 }, { key: "foo", value: "bar" }]);
1879
+ * const fooy = "fooy";
1880
+ * // "Foo"
1881
+ * type Foo = Replace<typeof fooy, "y", "">;
2069
1882
  * ```
2070
1883
  *
2071
- * Note: this is the inverse of `dictToKv()` function
1884
+ * Note: _the first match is replaced and all subsequent matches are ignored_
2072
1885
  */
2073
- declare function kvToDict<K extends string, V extends Narrowable, T extends readonly Readonly<{
2074
- key: K;
2075
- value: V;
2076
- }>[]>(kvArr: T): DictFromKv<T>;
1886
+ type Replace<S extends string, W extends string, P extends string> = S extends "" ? "" : W extends "" ? S : S extends `${infer F}${W}${infer E}` ? `${F}${P}${E}` : S;
2077
1887
 
2078
1888
  /**
2079
- * Type utility which converts `undefined[]` to `unknown[]`
1889
+ * Trims off whitespace on left of string
1890
+ * ```ts
1891
+ * // "foobar "
1892
+ * type T = TrimLeft<"\n\t foobar ">;
1893
+ * // string
1894
+ * type T = TrimLeft<string>;
1895
+ * ```
2080
1896
  */
2081
- type UndefinedArrayIsUnknown<T extends any[]> = undefined[] extends T ? unknown[] : T;
2082
- type AsArray<T, W extends boolean = false> = T extends any[] ? W extends true ? Widen<T> : T : W extends true ? UndefinedArrayIsUnknown<Widen<T>[]> : UndefinedArrayIsUnknown<T[]>;
1897
+ type TrimLeft<S extends string> = string extends S ? string : S extends `${Whitespace}${infer Right}` ? TrimLeft<Right> : S;
1898
+
2083
1899
  /**
2084
- * Ensures that any input passed in is passed back as an array:
2085
- *
2086
- * - if it was already an array than this just serves as an _identity_ function
2087
- * - if it was not then it wraps the element into a one element array of the
2088
- * given type
2089
- *
2090
- * Note: by default the _type_ of values will be intentionally widened so that the value "abc"
2091
- * is of type `string` not the literal `abc`. If you want to keep literal types then
2092
- * change the optional _widen_ parameter to _false_.
1900
+ * Provides the _left_ whitespace of a string
1901
+ * ```ts
1902
+ * // "\n\t "
1903
+ * type T = LeftWhitespace<"\n\t foobar">;
1904
+ * ```
2093
1905
  */
2094
- declare const asArray: <T extends Narrowable, W extends boolean = true>(thing: T, _widen?: W | undefined) => AsArray<T, W>;
1906
+ type LeftWhitespace<S extends string> = string extends S ? string : Replace<S, TrimLeft<S>, "">;
2095
1907
 
2096
1908
  /**
2097
- * Groups an array of data based on the value of a property
2098
- * in the objects within the array.
1909
+ * Trims off whitespace on left of string
2099
1910
  * ```ts
2100
- * const data = [ {}, {}, {} ];
2101
- *
1911
+ * // "\n foobar"
1912
+ * type T = TrimRight<"\n foobar \t">;
1913
+ * // string
1914
+ * type T = TrimRight<string>;
2102
1915
  * ```
2103
- *
2104
- * @ignore not implemented
2105
1916
  */
2106
- declare function groupBy<T extends Record<string, Narrowable>>(_data: Readonly<T[]>): void;
1917
+ type TrimRight<S extends string> = string extends S ? string : S extends `${infer Right}${Whitespace}` ? TrimRight<Right> : S;
2107
1918
 
2108
- type ExplicitFunction<P extends any[], R extends any> = (...args: P) => R;
2109
1919
  /**
2110
- * Takes a given function and converts it to an explicit representation
2111
- * where the generics represent the _parameter_ and _return_ typings.
1920
+ * Provides the _left_ whitespace of a string
1921
+ * ```ts
1922
+ * // "\n\t "
1923
+ * type T = LeftWhitespace<"\n\t foobar">;
1924
+ * ```
2112
1925
  */
2113
- declare function ExplicitFunction<T extends (...args: any[]) => any>(fn: T): ExplicitFunction<Parameters<T>, ReturnType<T>>;
1926
+ type RightWhitespace<S extends string> = string extends S ? string : Replace<S, TrimRight<S>, "">;
2114
1927
 
2115
1928
  /**
2116
- * **UniqueDictionary**
1929
+ * Type utility that provides the _length_ of a given string type in a way which
1930
+ * is _not_ limited to TS's recursive string length of roughly 48.
2117
1931
  *
2118
- * A dictionary converted by `arrayToObject()` which expects each key `S` to have a only a
2119
- * single/unique value.
1932
+ * ```ts
1933
+ * // 3
1934
+ * type Three = StringLength<"foo">;
1935
+ * ```
2120
1936
  */
2121
- type UniqueDictionary<S extends PropertyKey, N extends Narrowable, T extends Record<keyof T, N> & Record<S, any>> = {
2122
- [V in T as V[S]]: V;
2123
- };
1937
+ type StringLength<S extends string, R extends number[] = []> = S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}${infer _Sixth}${infer _Sevebnth}${infer _Eighth}${infer _Ninth}${infer _Tenth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}${infer _Sixth}${infer _Sevebnth}${infer _Eighth}${infer _Ninth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}${infer _Sixth}${infer _Sevebnth}${infer _Eighth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}${infer _Sixth}${infer _Sevebnth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}${infer _Sixth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer _Fifth}}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer _Fourth}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer _Third}${infer Rest}` ? StringLength<Rest, [...R, 1, 1, 1]> : S extends `${infer _First}${infer _Second}${infer Rest}` ? StringLength<Rest, [...R, 1, 1]> : S extends `${infer _First}${infer Rest}` ? StringLength<Rest, [...R, 1]> : [...R]["length"];
1938
+
2124
1939
  /**
2125
- * **GeneralDictionary**
2126
- *
2127
- * A dictionary converted by `arrayToObject()` which expects each key `S` to have an
2128
- * array of values.
1940
+ * Trims off blank spaces, `\n` and `\t` characters from both sides of a _string literal_.
1941
+ * ```ts
1942
+ * // "foobar"
1943
+ * type T = Trim<"\n\t foobar ">;
1944
+ * // string
1945
+ * type T = Trim<string>;
1946
+ * ```
2129
1947
  */
2130
- type GeneralDictionary<S extends PropertyKey, N extends Narrowable, T extends Record<keyof T, N> & Record<S, any>> = {
2131
- [V in T as V[S]]: V[];
2132
- };
2133
- type ArrayConverter<S extends PropertyKey, U extends boolean> =
1948
+ type Trim<S extends string> = string extends S ? string : S extends `${Whitespace}${infer Right}` ? Trim<Right> : S extends `${infer Left}${Whitespace}` ? Trim<Left> : S;
1949
+
2134
1950
  /**
2135
- * An `ArrayConverter` is the partial application of the `arrayToObject()`
2136
- * utility. At this point, the configuration is setup already and all that's
2137
- * left is to pass in an array of objects.
1951
+ * An email address
2138
1952
  */
2139
- <N extends Narrowable, T extends Record<keyof T, N> & Record<S, any>>(arr: readonly T[]) => true extends U ? UniqueDictionary<S, N, T> : GeneralDictionary<S, N, T>;
1953
+ type Email = `${string}@${string}.${string}`;
1954
+ type Zip5 = `${NumericString}${NumericString}${string}${NumericString}`;
1955
+ type Zip4 = `${NumericString}${string}`;
2140
1956
  /**
2141
- * Converts an array of objects into a dictionary by picking a property name contained
2142
- * by all objects and using that as the key to the dictionary.
2143
- *
2144
- * ```ts
2145
- * const arr = [
2146
- * { kind: "color", favorite: "blue", likes: 100 },
2147
- * { kind: "song", favorite: "some song", likes: 25 }
2148
- * ];
2149
- * const dict = arrayToObject("kind")(arr);
2150
- * ```
2151
- *
2152
- * This will produce a dictionary with keys of `color` and `song`.
1957
+ * A relatively strong type for Zip5 or Zip5+4 zip codes
2153
1958
  */
2154
- declare function arrayToObject<S extends PropertyKey, U extends boolean>(prop: S, unique?: U): ArrayConverter<S, true extends U ? true : false>;
1959
+ type ZipCode = Zip5 | `${Zip5}-${Zip4}`;
2155
1960
 
2156
- interface Box<T> {
2157
- __kind: "box";
2158
- value: T;
2159
- /**
2160
- * Unbox the boxed value in the narrowest possible type.
2161
- *
2162
- * **Note:** _if you want a wider type definition use `wide()`
2163
- * instead._
2164
- */
2165
- unbox(): T;
2166
- }
2167
- type BoxValue<T extends Box<any>> = T extends Box<infer V> ? V : never;
2168
- type BoxedFnParams<T extends Box<any>> = T extends Box<infer V> ? V extends (...args: infer A) => any ? A : [] : [];
2169
- type BoxedReturn<T extends Box<any>> = T extends Box<infer V> ? V extends Function ? ReturnType<T["value"]> : T["value"] : never;
2170
- type NarrowBox<T> = <N extends BoxedFnParams<Box<T>> | First<BoxedFnParams<Box<T>>>>() => N extends BoxedFnParams<Box<T>> ? T extends (...args: any[]) => any ? (...args: N) => Box<T>["unbox"] : never : (first: N, ...rest: AfterFirst<BoxedFnParams<Box<T>>>) => BoxedReturn<Box<T>>;
2171
1961
  /**
2172
- * Allows a value with an inner-type to be boxed into a dictionary
2173
- * so that this type inference is preserved with the help of
2174
- * [instantiation expressions](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7-beta/#instantiation-expressions).
2175
- *
2176
- * NOTE: this feature is immature at best right now
1962
+ * If **ALL CAPS** it converts to all lowercase; if not then it does nothing */
1963
+ type LowerAllCaps<T extends string> = AllCaps<T> extends true ? Lowercase<T> : T;
1964
+
1965
+ type Delimiter = "_" | "-" | " ";
1966
+ /** convert all delimiters to dashes */
1967
+ type DashDelim<T extends string> = T extends `${infer Begin}${" "}${infer Rest}` ? DashDelim<`${Begin}-${Rest}`> : T extends `${infer Begin}${"_"}${infer Rest}` ? DashDelim<`${Begin}-${Rest}`> : T;
1968
+ /**
1969
+ * Converts a string literal type to a **PascalCase** representation.
1970
+ * ```ts
1971
+ * // "FooBar"
1972
+ * type T = PascalCase<"fooBar">;
1973
+ * type T = PascalCase<"foo-bar">;
1974
+ * type T = PascalCase<"foo_bar">;
1975
+ * type T = PascalCase<"\n foo_bar \t">;
1976
+ * ```
2177
1977
  */
2178
- declare function box<T extends Narrowable>(value: T): Box<T>;
2179
- declare function isBox(thing: unknown): thing is Box<any>;
2180
- type Unbox<T> = T extends Box<infer U> ? U : T;
2181
- declare function unbox<T>(thing: T): Unbox<T>;
1978
+ type PascalCase<S extends string> = string extends S ? string : Trim<DashDelim<LowerAllCaps<S>>> extends `${infer Begin}${Delimiter}${infer Rest}` ? PascalCase<`${Capitalize<Begin>}${Capitalize<Rest>}`> : Capitalize<Trim<LowerAllCaps<S>>>;
1979
+
1980
+ type CamelCase<S extends string> = string extends S ? string : Uncapitalize<PascalCase<S>>;
2182
1981
 
2183
1982
  /**
2184
- * Build a _type_ from two run-time dictionaries.
2185
- *
2186
- * 1. The _first_ -- which is optional -- is interpreted as a _literal_ type definition
2187
- * 2. The _second_ dictionary is interpreted as a "wide" definition of prop types
1983
+ * Capitalize all words in a string
2188
1984
  */
2189
- declare function defineType<N extends Narrowable, TLiteral extends Record<string, N>>(literal?: TLiteral): <TWide extends object>(wide?: TWide) => ExpandRecursively<TWide & TLiteral>;
1985
+ type CapitalizeWords<S extends string> = S extends `${infer L} ${infer R}` ? `${CapitalizeWords<L>} ${CapitalizeWords<R>}` : S extends `${infer L},${infer R}` ? `${CapitalizeWords<L>},${CapitalizeWords<R>}` : S extends `${infer L}.${infer R}` ? `${CapitalizeWords<L>}.${CapitalizeWords<R>}` : Capitalize<S>;
1986
+
1987
+ type DashToSnake<T extends string> = T extends `${infer HEAD}-${infer TAIL}` ? DashToSnake<`${HEAD}_${TAIL}`> : T;
2190
1988
 
2191
1989
  /**
2192
- * An identity function for any type, with the goal of preserving literal type information
2193
- * whereever possible.
1990
+ * Indicates whether `T` has uppercase characters in it.
1991
+ * ```ts
1992
+ * // true
1993
+ * type T = HasUppercase<"Foobar">;
1994
+ * // false
1995
+ * type T = HasUppercase<"foobar">;
1996
+ * // "unknown"
1997
+ * type T = HasUppercase<string>;
1998
+ * ```
2194
1999
  */
2195
- declare const identity: <N extends Narrowable, T extends string | number | boolean | symbol | Record<any, N> | null | undefined>(v: T) => T;
2000
+ type HasUppercase<T extends string> = string extends T ? "unknown" : T extends `${string}${UpperAlpha}${string}` ? true : false;
2196
2001
 
2002
+ type _DU<T extends string> = T extends Lowercase<T> ? T : `-${Lowercase<T>}`;
2197
2003
  /**
2198
- * Takes an object as input --which has an `id` property and returns it as the same
2199
- * run-time content but with the _type_ of the `id` property being forced to a literal type
2004
+ * Converts uppercase characters to a dash and then the lowercase equivalent
2005
+ * ```ts
2006
+ * // "one-two-three"
2007
+ * type T = DashUppercase<"oneTwoThree">;
2008
+ * ```
2009
+ *
2010
+ * _Intended to be used as a lower level utility; prefer `Dasherize<T>` for more full-fledged
2011
+ * dash solution_.
2200
2012
  */
2201
- declare function idLiteral<T extends {
2202
- id: I;
2203
- }, I extends PropertyKey>(o: T): T & {
2204
- id: T["id"];
2205
- };
2013
+ type DashUppercase<T extends string> = HasUppercase<T> extends false ? T : T extends `${infer C0}${infer C1}${infer R}` ? `${_DU<C0>}${_DU<C1>}${DashUppercase<R>}` : T extends `${infer C0}${infer R}` ? `${_DU<C0>}${DashUppercase<R>}` : "";
2014
+
2015
+ type OneToOne = `1:1`;
2016
+ type OneToMany = `1:M`;
2017
+ type OneToZero = `1:0`;
2018
+ type ZeroToOne = `0:1`;
2019
+ type ZeroToMany = `0:M`;
2020
+ type ZeroToZero = `0:0`;
2021
+ type ManyToMany = "M:M";
2022
+ type ManyToOne = "M:1";
2023
+ type ManyToZero = "M:0";
2024
+ type CardinalityNode = "0" | "1" | "M";
2206
2025
  /**
2207
- * Takes an object as input --which has an `name` property and returns it as the same
2208
- * run-time content but with the _type_ of the `name` property being forced to a literal type
2026
+ * Cardinality which expects a singular input and requires
2027
+ * 1 or many outputs.
2028
+ *
2029
+ * Note: choose `CardinalityFilter1` if you want to allow output
2030
+ * to have no outputs.
2209
2031
  */
2210
- declare function nameLiteral<T extends {
2211
- name: I;
2212
- }, I extends PropertyKey>(o: T): T & {
2213
- name: T["name"];
2214
- };
2032
+ type Cardinality1 = OneToOne | OneToMany;
2215
2033
  /**
2216
- * Takes an object as input --which has an `kind` property and returns it as the same
2217
- * run-time content but with the _type_ of the `kind` property being forced to a literal type
2034
+ * Cardinality which expects a singular input and maps to 0,
2035
+ * 1, or many outputs.
2218
2036
  */
2219
- declare function kindLiteral<T extends {
2220
- kind: I;
2221
- }, I extends PropertyKey>(o: T): T & {
2222
- kind: T["kind"];
2223
- };
2224
- declare function idTypeGuard<T extends {
2225
- id: I;
2226
- }, I extends PropertyKey>(_o: T): _o is T & {
2227
- id: I;
2228
- };
2037
+ type CardinalityFilter1 = OneToOne | OneToMany | OneToZero;
2229
2038
  /**
2230
- * Takes an object as input and infers the narrow literal types of the property
2231
- * values on the object.
2232
- *
2233
- * > Note: this addresses this [a known TS gap](https://github.com/microsoft/TypeScript/issues/30680).
2234
- * > Hopefully at some point this will be addressed in the language.
2039
+ * Cardinality which expects a singular input which is allowed to be
2040
+ * _undefined_ or the expected type.
2235
2041
  */
2236
- declare function literal<N extends Narrowable, T extends Record<keyof T, N>>(obj: T): T;
2237
-
2042
+ type Cardinality0 = ZeroToOne | ZeroToMany | OneToOne | OneToMany;
2238
2043
  /**
2239
- * **Suggest**
2240
- *
2241
- * Type utility that helps to build a enumerated set
2242
- * of string literals which _could_ be the value for
2243
- * a string based property but _allows_ a string that
2244
- * is not part of the suggestion to be typed in too.
2044
+ * Cardinality which expects a singular input -- which is allowed to be
2045
+ * _undefined_ -- and maps to 0,
2046
+ * 1, or many outputs.
2245
2047
  */
2246
- type Suggest<T extends string> = T | (string & {});
2048
+ type CardinalityFilter0 = ZeroToOne | ZeroToMany | OneToOne | OneToMany | OneToZero | ZeroToZero;
2049
+ type CardinalityExplicit = `${number}:${number}`;
2247
2050
  /**
2248
- * **SuggestNumeric**`<T>`
2249
- *
2250
- * Type utility that helps to build a enumerated set
2251
- * of numeric literals which _could_ be the value for
2252
- * a number based property but _allows_ a number that
2253
- * is not part of the suggestion to be typed in too.
2051
+ * Cardinality of any sort between two types
2254
2052
  */
2255
- type SuggestNumeric<T extends number> = T | (number & {});
2256
-
2257
- type Condition<TInput extends Narrowable, TResult extends boolean> = (input: TInput) => TResult;
2258
- declare const condition: <TInput extends Narrowable, C extends Condition<Narrowable, boolean>>(c: C, input: TInput) => boolean;
2259
-
2260
- declare function isArray<T>(i: T): IsArray<T>;
2053
+ type Cardinality = CardinalityFilter0 | CardinalityFilter1 | ManyToMany | ManyToOne | ManyToZero | CardinalityExplicit;
2054
+ type CardinalityTuple<T extends Cardinality> = UnionToTuple<T>;
2261
2055
  /**
2262
- * **ifArray**(T, IF, ELSE)
2263
- *
2264
- * A utility which evaluates a type `T` for whether it is an array and then
2056
+ * The first or _input_ part of the Cardinality relationship
2265
2057
  */
2266
- declare function ifArray<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(val: T, isAnArray: <N extends T & readonly any[]>(arr: N) => IF, isNotAnArray: <N extends Exclude<T, any[]>>(nonArr: N) => ELSE): IfArray<T, IF, ELSE>;
2267
- declare function ifArrayPartial<T extends Narrowable>(): <IF extends Narrowable, ELSE extends Narrowable>(isAnArray: <N extends T & readonly any[]>(arr: N) => IF, isNotAnArray: <N_1 extends Exclude<T, any[]>>(nonArr: N_1) => ELSE) => <V extends T>(val: V) => IfArray<V, IF, ELSE>;
2268
-
2058
+ type CardinalityIn<T extends Cardinality> = T extends `${infer IN}:${string}` ? IN : never;
2269
2059
  /**
2270
- * Runtime and type checks whether a variable is a boolean value.
2060
+ * The second or _output_ part of the Cardinality relationship
2271
2061
  */
2272
- declare function isBoolean<T extends any>(i: T): IsBoolean<T>;
2062
+ type CardinalityOut<T extends Cardinality> = T extends `${string}:${infer OUT}` ? OUT : never;
2063
+ type CardinalityInput<T, C extends Cardinality> = CardinalityTuple<C>[0] extends 0 ? T | undefined : CardinalityTuple<C>[0] extends 1 ? T : T[];
2064
+
2273
2065
  /**
2274
- * **ifBoolean**
2275
- *
2276
- * Strongly type-aware conditional statement which checks whether a value is
2277
- * a _boolean_ and returns one of two values (strongly typed) based on the evaluation
2278
- * of this criteria.
2066
+ * Converts a string literal into a _dasherized_ format while ignoring _exterior_ whitespace.
2279
2067
  *
2280
- * @param val the value being tested
2281
- * @param ifVal the value (strongly typed) returned if val is _boolean_
2282
- * @param elseVal the value (strongly typed) returned if val is NOT a _boolean
2068
+ * ```ts
2069
+ * // "foo-bar"
2070
+ * type Dash = Dasherize<"foo_bar">;
2071
+ * type Dash = Dasherize<"fooBar">;
2072
+ * type Dash = Dasherize<"FooBar">;
2073
+ * // "\n foo-bar \t"
2074
+ * type Dash = Dasherize<"\n foo bar \t">;
2075
+ * ```
2283
2076
  */
2284
- declare function ifBoolean<T, IF, ELSE>(val: T, ifVal: IF, elseVal: ELSE): IsBoolean<T> extends true ? IF : ELSE;
2077
+ type Dasherize<S extends string> = string extends S ? string : DashUppercase<Trim<LowerAllCaps<S>>> extends `${infer Begin}${"_" | " "}${infer Rest}` ? Dasherize<`${Lowercase<Begin>}-${Rest}`> : Lowercase<DashUppercase<Uncapitalize<Trim<LowerAllCaps<S>>>>>;
2285
2078
 
2286
- declare function isFalse<T>(i: T): IsFalse<T>;
2287
2079
  /**
2288
- * **ifTrue**
2289
- *
2290
- * Strongly type-aware conditional statement which checks whether a value is
2291
- * a _true_ and returns one of two values (strongly typed) based on the evaluation
2292
- * of this criteria.
2080
+ * **EnsureLeading**`<T, U>`
2293
2081
  *
2294
- * @param val the value being tested
2295
- * @param ifVal the value (strongly typed) returned if val is _true_ value
2296
- * @param elseVal the value (strongly typed) returned if val is NOT a _true_ value
2082
+ * Will ensure that `T` ends with the _substring_ `U` when
2083
+ * both are string literals.
2297
2084
  *
2298
- * Note: at runtime there's no way to distinguish if the value was widely or loosely
2299
- * typed so unlike the type utility there is no "MAYBE" state but if a wide type if
2300
- * encountered the _type_ will the union of `IF` and `ELSE`.
2085
+ * ```ts
2086
+ * type T = " World";
2087
+ * type U = "Hello";
2088
+ * // "Hello World"
2089
+ * type R = EnsureLeading<T,U>;
2090
+ * ```
2301
2091
  */
2302
- declare function ifFalse<T extends boolean, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifVal: IF, elseVal: ELSE): IfFalse<T, IF, ELSE, IF | ELSE>;
2092
+ type EnsureLeading<T extends string, U extends string> = IfLiteral<T, string extends U ? never : T extends `${U}${string}` ? T : `${U}${T}`, string>;
2303
2093
 
2304
- type IsFunction<T> = T extends FunctionType ? true : false;
2305
- type HybridFunction<TProps extends {}> = (<TArgs extends any[]>(...args: TArgs) => any) & TProps;
2306
- type SimpleFunction = <TArgs extends any[]>(...args: TArgs) => any;
2307
- type AnyFunction<TProps extends {} | never = never> = TProps extends {} ? HybridFunction<TProps> : SimpleFunction;
2308
2094
  /**
2309
- * Checks whether a passed in value is a function and ensures run-time and types
2310
- * are consistent.
2095
+ * Returns true or false value based on whether the string literal is capitalized.
2311
2096
  * ```ts
2312
2097
  * // true
2313
- * const yup = isFunction(() => "hello world");
2098
+ * type T2 = IsCapitalized<"One">;
2099
+ * // false
2100
+ * type T1 = IsCapitalized<"one">;
2101
+ * // "unknown"
2102
+ * const a: string = "Hi";
2103
+ * type T3 = IsCapitalized<typeof a>;
2314
2104
  * ```
2315
2105
  *
2316
- * Note: the runtime `typeof [variable]` will correctly say "function" when a function is
2317
- * encountered but if that function also has object types defined then the type will be a big
2318
- * and ugly union type. This function will give you a proper boolean value in both cases.
2106
+ * Note: _if the value passed in is a "string" then the result will be "unknown"_
2319
2107
  */
2320
- declare function isFunction<T>(input: T): IsFunction<T>;
2108
+ type IsCapitalized<T extends string> = string extends T ? "unknown" : T extends Capitalize<T> ? true : false;
2321
2109
 
2322
- type IsNull<T> = T extends null ? true : false;
2323
- declare function isNull<T extends Narrowable>(i: T): T extends null ? true : false;
2324
2110
  /**
2325
- * **ifNull**
2326
- *
2327
- * Strongly type-aware conditional statement which checks whether a value is
2328
- * Null and returns one of two values (strongly typed) based on the evaluation
2329
- * of this criteria.
2330
- *
2331
- * @param val the value being tested
2332
- * @param ifVal the value (strongly typed) returned if val is `null`
2333
- * @param elseVal the value (strongly typed) returned if val is NOT `null`
2334
- */
2335
- declare function ifNull<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifVal: IF, elseVal: ELSE): IsNull<T> extends true ? IF : ELSE;
2111
+ * **KebabCase<T>** is an _alias_ for **Dasherize<T>**.
2112
+ * ```ts
2113
+ * // "foo-bar"
2114
+ * type Kebab = KebabCase<"foo_bar">;
2115
+ * type Kebab = KebabCase<"fooBar">;
2116
+ * type Kebab = KebabCase<"FooBar">;
2117
+ * // "\n foo-bar \t"
2118
+ * type Kebab = KebabCase<"\n foo bar \t">;
2119
+ * ``` */
2120
+ type KebabCase<T extends string> = Dasherize<T>;
2336
2121
 
2337
- type IsNumber<T> = T extends number ? true : false;
2338
- declare function isNumber<T>(i: T): T extends number ? true : false;
2122
+ type Consonant = "b" | "c" | "d" | "f" | "g" | "h" | "j" | "k" | "l" | "m" | "n" | "p" | "q" | "r" | "s" | "t" | "v" | "w" | "x" | "z" | "y";
2123
+ type Exceptions = "photo => photos" | "piano => pianos" | "halo => halos" | "foot => feet" | "man => men" | "woman => women" | "person => people" | "mouse => mice" | "series => series" | "sheep => sheep" | "money => monies" | "deer => deer";
2124
+ type SingularException<T = Exceptions> = T extends `${infer SINGULAR} => ${infer PLURAL}` ? SINGULAR : never;
2125
+ type PluralException<T extends SingularException, E extends Exceptions = Exceptions> = E extends `${T} => ${infer PLURAL}` ? PLURAL : never;
2126
+ type SingularNoun = "s" | "sh" | "ch" | "x" | "z" | "o";
2127
+ type F = "f" | "fe";
2128
+ type Y = `${Consonant}y`;
2129
+ type RemoveTrailingY<T> = T extends `${infer HEAD}y` ? HEAD : T;
2130
+ /** validates that a word ends with a pluralization exception */
2131
+ type isException<T extends string> = T extends SingularException ? T : never;
2132
+ /** validates that a string literal ends in "is" */
2133
+ type EndsIn_IS<T extends string> = T extends `${infer HEAD}is` ? T : never;
2134
+ /** validates that a string literal is a singular noun */
2135
+ type EndsInSingularNoun<T extends string> = T extends `${infer HEAD}${SingularNoun}` ? T : never;
2136
+ /** validates that a string literal ends in "f" or "fe" */
2137
+ type EndsIn_F<T extends string> = T extends `${infer HEAD}${F}` ? T : never;
2138
+ /** validates that a string literal ends a consonant followed by "y" */
2139
+ type EndsIn_Y<T extends string> = T extends `${infer HEAD}${Y}` ? T : never;
2339
2140
  /**
2340
- * **ifNumber**
2341
- *
2342
- * Strongly type-aware conditional statement which checks whether a value is
2343
- * a _number_ and returns one of two values (strongly typed) based on the evaluation
2344
- * of this criteria.
2345
- *
2346
- * @param val the value being tested
2347
- * @param ifVal the value (strongly typed) returned if val is number
2348
- * @param elseVal the value (strongly typed) returned if val is NOT a number
2141
+ * strings which end in the letters "is" should have an "es" added to the end
2349
2142
  */
2350
- declare function ifNumber<T, IF, ELSE>(val: T, ifVal: IF, elseVal: ELSE): IsNumber<T> extends true ? IF : ELSE;
2351
-
2352
- type ObjectType = Not<Record<string, Narrowable>, FunctionType>;
2143
+ type PluralizeEndingIn_IS<T extends string> = T extends `${infer HEAD}is` ? `${HEAD}ises` : T;
2353
2144
  /**
2354
- * Detects whether the passed in `v` is of type "object" where an object
2355
- * is defined to be a string keyed dictionary style object. This means that
2356
- * arrays are excluded, as well as functions which also have properties hanging
2357
- * off of them.
2145
+ * singular nouns should have "es" added to the end
2358
2146
  */
2359
- declare function isObject<T extends unknown>(i: T): IsObject<T>;
2360
-
2147
+ type PluralizeEndingSingularNoun<T extends string> = T extends `${infer HEAD}${SingularNoun}` ? `${T}es` : T;
2361
2148
  /**
2362
- * **IsString**
2363
- *
2364
- * Type utility which returns true/false based on whether `T` is a
2365
- * string (wide or narrow).
2149
+ * strings which end in the letters "f" or "fe" should have "ves" replace the ending
2366
2150
  */
2367
- type IsString<T> = T extends string ? true : false;
2151
+ type PluralizeEnding_F<T extends string> = T extends `${infer HEAD}${F}` ? `${HEAD}ves` : T;
2368
2152
  /**
2369
- * **IfString**
2370
- *
2371
- * Type utility which determines if `T` is a _string_ (wide or narrow) and
2372
- * returns `IF` type if it is, otherwise returns the type `ELSE`.
2153
+ * singular nouns should have "es" added to the end
2373
2154
  */
2374
- type IfString<T extends Narrowable, //
2375
- IF extends Narrowable, ELSE extends Narrowable> = IsString<T> extends true ? IF : IsString<T> extends false ? ELSE : IF | ELSE;
2155
+ type PluralizeEndingIn_Y<T extends string> = T extends `${infer HEAD}${Y}` ? `${RemoveTrailingY<T>}ies` : T;
2156
+ type Pluralize<T extends string> = T extends isException<T> ? PluralException<T> : T extends EndsIn_IS<T> ? PluralizeEndingIn_IS<T> : T extends EndsInSingularNoun<T> ? PluralizeEndingSingularNoun<T> : T extends EndsIn_F<T> ? PluralizeEnding_F<T> : T extends EndsIn_Y<T> ? PluralizeEndingIn_Y<T> : `${T}s`;
2376
2157
 
2158
+ /** convert space to dash */
2159
+ type SpaceToDash<T extends string> = T extends `${infer Begin}${" "}${infer Rest}` ? SpaceToDash<`${Begin}-${Rest}`> : T;
2377
2160
  /**
2378
- * **isString**
2379
- *
2380
- * Returns true or false on whether the passed in parameter is a
2381
- * string (either a wide string or a string literal).
2382
- *
2383
- * The boolean return is traceable by the type system as well as the
2384
- * runtime system.
2385
- */
2386
- declare function isString<T>(i: T): IsString<T>;
2161
+ * Converts a string literal type to _snake_case_.
2162
+ * ```ts
2163
+ * // "foo_bar"
2164
+ * type T = SnakeCase<"fooBar">;
2165
+ * type T = SnakeCase<"FooBar">;
2166
+ * type T = SnakeCase<"foo-bar">;
2167
+ * type T = SnakeCase<"\n foo bar \t">;
2168
+ * ``` */
2169
+ type SnakeCase<S extends string> = string extends S ? string : DashUppercase<Uncapitalize<SpaceToDash<Trim<LowerAllCaps<S>>>>> extends `${infer Begin}${"-"}${infer Rest}` ? SnakeCase<`${Lowercase<Begin>}_${Rest}`> : Lowercase<DashUppercase<Uncapitalize<Trim<LowerAllCaps<S>>>>>;
2170
+
2387
2171
  /**
2388
- * **ifString**
2389
- *
2390
- * Strongly type-aware conditional statement which checks whether a value is
2391
- * a _string_ and returns one of two values (strongly typed) based on the evaluation
2392
- * of this criteria.
2172
+ * **StripStarting**`<T, U>`
2393
2173
  *
2394
- * @param val the value being tested for being a string
2395
- * @param ifVal the value (strongly typed) returned if val is _string_
2396
- * @param elseVal the value (strongly typed) returned if val is NOT a _string
2174
+ * Will strip off of `T` the starting string defined by `U` when
2175
+ * both are string literals.
2176
+ * ```ts
2177
+ * type T = "Hello World";
2178
+ * type U = "Hello ";
2179
+ * // "World"
2180
+ * type R = StripStarting<T,U>;
2181
+ * ```
2397
2182
  */
2398
- declare function ifString<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifVal: IF, elseVal: ELSE): IfString<T, IF, ELSE>;
2399
-
2400
- declare function isSymbol<T>(i: T): T extends symbol ? true : false;
2183
+ type StripLeading<T extends string, U extends string> = IfLiteral<T, string extends U ? never : T extends `${U}${infer After}` ? After : T, string>;
2401
2184
 
2185
+ type NetworkProtocol = "http" | "https" | "file" | "ws" | "wss";
2402
2186
  /**
2403
- * Run-time and type checking of whether a variable is `true`.
2187
+ * A literal variant of _string_ which is meant to represent a domain name
2188
+ * (e.g., `www.someplace.com`, etc.)
2404
2189
  */
2405
- declare function isTrue<T extends Narrowable>(i: T): IsTrue<T>;
2190
+ type DomainName = `${AlphaNumeric}${string}.${AlphaNumeric}${string}` | `${AlphaNumeric}${string}.${AlphaNumeric}${string}.${string}` | `${AlphaNumeric}${string}.${AlphaNumeric}${string}.${string}.${string}`;
2191
+ type RelativeUrl = `${VariableName | "/"}`;
2406
2192
  /**
2407
- * **ifTrue**
2193
+ * A literal variant of _string_ which forces a string to follow conventions
2194
+ * for a fully qualified URL like `https://google.com`. It can't ensure the
2195
+ * type is fully valid but does help to avoid some typos.
2196
+ */
2197
+ type FullyQualifiedUrl = `${NetworkProtocol}://${Ipv4 | DomainName}/${string}`;
2198
+ type UrlBuilder = (<P extends NetworkProtocol, D extends DomainName, B extends RelativeUrl>(protocol: P, domain: D, basePath: B) => `${P}://${D}/${B}`) | (<U extends RelativeUrl>(url: U) => U);
2199
+
2200
+ /**
2201
+ * **ensureLeading**(content, strip)
2408
2202
  *
2409
- * Strongly type-aware conditional statement which checks whether a value is
2410
- * _true_.
2203
+ * Runtime utility which ensures that last part of a string -- `content` -- has the
2204
+ * substring `ensure` at the end and adds it if not present.
2205
+ */
2206
+ declare function ensureLeading<T extends string, U extends string>(content: T, ensure: U): EnsureLeading<T, U>;
2207
+
2208
+ /**
2209
+ * **Suggest**
2411
2210
  *
2412
- * @param val the value being tested
2413
- * @param ifVal the value (strongly typed) returned if val is _true_ value
2414
- * @param elseVal the value (strongly typed) returned if val is NOT a _true_ value
2211
+ * Type utility that helps to build a enumerated set
2212
+ * of string literals which _could_ be the value for
2213
+ * a string based property but _allows_ a string that
2214
+ * is not part of the suggestion to be typed in too.
2215
+ */
2216
+ type Suggest<T extends string> = T | (string & {});
2217
+ /**
2218
+ * **SuggestNumeric**`<T>`
2415
2219
  *
2416
- * Note: at runtime there's no way to distinguish if the value was widely or loosely
2417
- * typed so unlike the type utility there is no "MAYBE" state but if a wide type if
2418
- * encountered the _type_ will the union of `IF` and `ELSE`.
2220
+ * Type utility that helps to build a enumerated set
2221
+ * of numeric literals which _could_ be the value for
2222
+ * a number based property but _allows_ a number that
2223
+ * is not part of the suggestion to be typed in too.
2419
2224
  */
2420
- declare function ifTrue<T extends boolean, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifVal: IF, elseVal: ELSE): IfTrue<T, IF, ELSE, IF | ELSE>;
2225
+ type SuggestNumeric<T extends number> = T | (number & {});
2421
2226
 
2422
- declare function isUndefined<T extends Narrowable>(i: T): undefined extends T ? true : false;
2423
2227
  /**
2424
- * **ifUndefined**
2228
+ * **wide**
2425
2229
  *
2426
- * Strongly type-aware conditional statement which checks whether a value is
2427
- * _undefined_ and returns one of two values (strongly typed) based on the evaluation
2428
- * of this criteria.
2230
+ * Provides a dictionary of _wide_ types
2231
+ */
2232
+ declare const wide: {
2233
+ readonly boolean: boolean;
2234
+ readonly string: string;
2235
+ readonly number: number;
2236
+ readonly symbol: Symbol;
2237
+ readonly null: null;
2238
+ readonly undefined: undefined;
2239
+ };
2240
+
2241
+ type Condition<TInput extends Narrowable, TResult extends boolean> = (input: TInput) => TResult;
2242
+ declare const condition: <TInput extends Narrowable, C extends Condition<Narrowable, boolean>>(c: C, input: TInput) => boolean;
2243
+
2244
+ /**
2245
+ * **TypeGuard**
2429
2246
  *
2430
- * @param val the value being tested
2431
- * @param ifVal the value (strongly typed) returned if val is `undefined`
2432
- * @param elseVal the value (strongly typed) returned if val is NOT `undefined`
2247
+ * a typing for a **TS** type-guard which evaluates an _unknown_ input
2248
+ * and determines if it is of type `T`.
2433
2249
  */
2434
- declare function ifUndefined<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(val: T, ifVal: IF, elseVal: ELSE): IsUndefined<T> extends true ? IF : ELSE;
2250
+ type TypeGuard<T> = (thing: unknown) => thing is T;
2435
2251
 
2436
2252
  type Type<T extends any, V extends Function> = {
2437
2253
  name: string;
@@ -2541,4 +2357,360 @@ interface IFluentConfigurator<C> {
2541
2357
  */
2542
2358
  declare function FluentConfigurator<I>(initial?: I): IFluentConfigurator<{}>;
2543
2359
 
2544
- export { AfterFirst, AllCaps, Alpha, AlphaNumeric, AnyFunction, Api, ApiFunction, ApiValue, AppendToDictionary, AppendToObject, ArrConcat, Array$1 as Array, ArrayConverter, AsArray, AsFinalizedConfig, AssertExtends, Box, BoxValue, BoxedFnParams, BoxedReturn, Bracket, Break, CamelCase, CapitalizeWords, Cardinality, Cardinality0, Cardinality1, CardinalityExplicit, CardinalityFilter0, CardinalityFilter1, CardinalityIn, CardinalityInput, CardinalityNode, CardinalityOut, CardinalityTuple, ClosingBracket, Condition, ConditionFilter, Configurator, ConfiguredMap, Constructor, Contains, DEFAULT_MANY_TO_ONE_MAPPING, DEFAULT_ONE_TO_MANY_MAPPING, DEFAULT_ONE_TO_ONE_MAPPING, DashToSnake, DashUppercase, Dasherize, DecomposeMapConfig, DefaultManyToOneMapping, DefaultOneToManyMapping, DefaultOneToOneMapping, DefinePropertiesApi, DictArrApi, DictArray, DictArrayFilterCallback, DictArrayKv, DictChangeValue, DictFromKv, DictKvTuple, DictPartialApplication, DictPrependWithFn, DictReturnValues, DomainName, DynamicRule, DynamicRuleSet, Email, EndsWith, EnumValues, Equal, ExpandRecursively, ExpectExtends, ExplicitFunction, Extends, FilterContains, FilterDefn, FilterEnds, FilterEquals, FilterFn, FilterGreaterThan, FilterIs, FilterLessThan, FilterNotEqual, FilterStarts, FilterTuple, FinalReturn, FinalizedMapConfig, First, FirstKey, FirstKeyValue, FirstOfEach, FirstOrUndefined, FirstString, FluentConfigurator, FluentFunction, FnShape, FromDictArray, FullyQualifiedUrl, FunctionType, GeneralDictionary, Get, HasUppercase, HybridFunction, IConfigurator, IFluentConfigurator, If, IfArray, IfBooleanLiteral, IfEndsWith, IfExtends, IfExtendsThen, IfFalse, IfLiteral, IfNumericLiteral, IfObject, IfOptionalLiteral, IfReadonlyArray, IfScalar, IfStartsWith, IfStringLiteral, IfTrue, IfUndefined, Include, Includes, IntersectingKeys, Ipv4, IsArray, IsBoolean, IsBooleanLiteral, IsCapitalized, IsFalse, IsFunction, IsLiteral, IsNull, IsNumber, IsNumericLiteral, IsObject, IsOptionalLiteral, IsReadonlyArray, IsScalar, IsStringLiteral, IsTrue, IsUndefined, KebabCase, KeyValue, KeyedRecord, Keys, KeysWithValue, KvFrom, KvTuple, LastInUnion, LeftWhitespace, Length, LogicFunction, LogicalCombinator, LowerAllCaps, LowerAlpha, ManyToMany, ManyToOne, ManyToZero, MapCard, MapCardinality, MapCardinalityFrom, MapCardinalityIllustrated, MapConfig, MapFn, MapFnInput, MapFnOutput, MapIR, MapInput, MapInputFrom, MapOR, MapOutput, MapOutputFrom, MapTo, Mapper, MapperApi, MaybeFalse, MaybeTrue, Mutable, MutableProps, NarrowBox, Narrowable, NarrowlyContains, NetworkProtocol, NonAlpha, NonNumericKeys, NonStringKeys, Not, NotEqual, NotFilter, Numeric, NumericFilter, NumericKeys, NumericString, ObjectType, OneToMany, OneToOne, OneToZero, Opaque, OpeningBracket, OptRequired, OptionalKeys, OptionalProps, Or, Parenthesis, PascalCase, Pluralize, PrivateKey, PrivateKeys, PublicKeys, Punctuation, PureFluentApi, RelativeUrl, Replace, RequireProps, RequiredKeys, RequiredProps, Retain, RightWhitespace, RuleDefinition, RuntimeProp, RuntimeType, SameKeys, SecondOfEach, SimpleFunction, SimplifyObject, SnakeCase, SpecialCharacters, Split, StartsWith, StringDelimiter, StringFilter, StringKeys, StringLength, Suggest, SuggestNumeric, ToFluent, Transformer, Trim, TrimLeft, TrimRight, TupleToUnion, Type, TypeApi, TypeDefault, TypeDefinition, TypeGuard, TypeOptions, Unbox, UndefinedArrayIsUnknown, UndefinedTreatment, UndefinedValue, UnionToIntersection, UnionToTuple, UniqueDictionary, UniqueForProp, Uniqueness, UnwrapNot, UpperAlpha, UrlBuilder, VariableName, Where, WhereNot, Whitespace, Widen, WithNumericKeys, WithStringKeys, WithValue, ZeroToMany, ZeroToOne, ZeroToZero, ZipCode, and, api, arrayToKeyLookup, arrayToObject, asArray, box, condition, createFnWithProps, defineProperties, defineType, dictArr, dictToKv, dictionaryTransform, entries, filter, filterDictArray, fnWithProps, groupBy, idLiteral, idTypeGuard, identity, ifArray, ifArrayPartial, ifBoolean, ifFalse, ifNull, ifNumber, ifString, ifTrue, ifUndefined, isArray, isBoolean, isBox, isFalse, isFunction, isNotFilter, isNull, isNumber, isNumericFilter, isObject, isString, isSymbol, isTrue, isType, isUndefined, keys, kindLiteral, kv, kvToDict, literal, mapTo, mapToDict, mapToFn, mapValues, nameLiteral, not, or, readonlyFnWithProps, ruleSet, strArrayToDict, type, typeApi, unbox, withValue };
2360
+ type Widen<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends readonly string[] ? string[] : T extends readonly number[] ? number[] : T extends readonly boolean[] ? boolean[] : T extends readonly AnyFunction[] ? AnyFunction[] : T extends readonly any[] ? TupleToUnion<T>[] : T extends {} ? {} : T;
2361
+
2362
+ /**
2363
+ * **Includes**`<TSource, TValue>`
2364
+ *
2365
+ * Type utility which returns `true` or `false` based on whether `TValue` is found
2366
+ * in `TSource`. Where `TSource` can be a string literal or an array of string literals.
2367
+ *
2368
+ * **Note:** if the source is a _wide_ type (aka, `string` or `string[]`) then there is
2369
+ * no way to know at design-time whether the value includes `TValue` and so it will return
2370
+ * a type of `boolean`.
2371
+ */
2372
+ type Includes<TSource extends string | readonly string[], TValue extends string> = TSource extends string[] ? IsStringLiteral<TupleToUnion<TSource>> extends true ? IsLiteral<TValue> extends true ? TValue extends TupleToUnion<TSource> ? true : false : boolean : boolean : TSource extends string ? IsLiteral<TSource> extends true ? IsLiteral<TValue> extends true ? TSource extends `${string}${TValue}${string}` ? true : false : boolean : boolean : boolean;
2373
+
2374
+ type IsScalar<T extends Narrowable> = [T] extends [string] ? true : [T] extends [number] ? true : [T] extends [boolean] ? true : false;
2375
+ /**
2376
+ * **IfScalar**`<T, IF, ELSE>`
2377
+ *
2378
+ * Branch type utility which returns `IF` when `T` is a scalar value (aka, string, number, or boolean) and `ELSE` otherwise
2379
+ */
2380
+ type IfScalar<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable> = IsScalar<T> extends true ? IF : ELSE;
2381
+
2382
+ /**
2383
+ * **HasParameters**`<T>`
2384
+ *
2385
+ * Type utility which detects if `T` is both a function and whether that
2386
+ * function has at least one type parameter.
2387
+ * ```ts
2388
+ * const fn = (foo: string) => `${foo}bar`;
2389
+ * // true
2390
+ * type P = HasParameters<typeof fn>;
2391
+ * ```
2392
+ */
2393
+ type HasParameters<T extends Narrowable> = T extends AnyFunction ? IsEqual<Length<Parameters<T>>, 0> extends true ? false : true : false;
2394
+
2395
+ /**
2396
+ * **IsObject**
2397
+ *
2398
+ * Boolean type utility used to check whether a type `T` is an object
2399
+ */
2400
+ type IsObject<T> = Mutable<T> extends Record<string, any> ? T extends FunctionType ? false : Mutable<T> extends any[] ? false : true : false;
2401
+ /**
2402
+ * **IfObject**
2403
+ *
2404
+ * Branch type utility with return `IF` when `T` extends an object type
2405
+ * and `ELSE` otherwise
2406
+ */
2407
+ type IfObject<T, IF extends Narrowable, ELSE extends Narrowable> = IsObject<T> extends true ? IF : ELSE;
2408
+
2409
+ /**
2410
+ * **StartsWith**<TValue, TStartsWith>
2411
+ *
2412
+ * A type utility which checks whether `T` _starts with_ the string literal `U`.
2413
+ *
2414
+ * If both `T` and `U` are string literals then the type system will resolve
2415
+ * to a literal `true` or `false` but if either is not a literal that it will
2416
+ * just resolve to `boolean` as the value can not be known at design time..
2417
+ */
2418
+ type StartsWith<TValue extends string, TStartsWith extends string> = IsStringLiteral<TStartsWith> extends true ? IsStringLiteral<TValue> extends true ? TValue extends `${TStartsWith}${string}` ? true : false : boolean : boolean;
2419
+ /**
2420
+ * **IfStartsWith**<TValue, TStartsWith, IF, ELSE, MAYBE>
2421
+ *
2422
+ * Type utility which converts type to `IF` type _if_ TValue _starts with_ `TStartsWith` but
2423
+ * otherwise converts type to `ELSE`.
2424
+ *
2425
+ * Note, that there is also an optional `MAYBE` type
2426
+ * which can be stated for cases where TValue or TStartsWith _might_ be the wider `string`
2427
+ * type and therefore the type is unknown at design time.
2428
+ */
2429
+ type IfStartsWith<TValue extends string, TStartsWith extends string, IF extends Narrowable, ELSE extends Narrowable> = StartsWith<TValue, TStartsWith> extends true ? IF : StartsWith<TValue, TStartsWith> extends false ? ELSE : IF | ELSE;
2430
+
2431
+ /**
2432
+ * **EndsWith**<T,U>
2433
+ *
2434
+ * A type utility which checks whether `T` _ends with_ the string literal `U`.
2435
+ *
2436
+ * If both `T` and `U` are string literals then the type system will resolve
2437
+ * to a literal `true` or `false` but if either is not a literal that it will
2438
+ * just resolve to `boolean` as the value can not be known at design time..
2439
+ */
2440
+ type EndsWith<TValue extends string, TEndsWith extends string> = IsStringLiteral<TEndsWith> extends true ? IsStringLiteral<TValue> extends true ? TValue extends `${string}${TEndsWith}` ? true : false : boolean : boolean;
2441
+ /**
2442
+ * **IfEndsWith**<TValue, TEndsWith, IF, ELSE, MAYBE>
2443
+ *
2444
+ * Type utility which converts type to `IF` type _if_ `TValue` _ends with_ `TEndsWith` but
2445
+ * otherwise converts type to `ELSE`. If there are wide types in the mix then the type will
2446
+ * result in the union of IF and ELSE.
2447
+ */
2448
+ type IfEndsWith<TValue extends string, TEndsWith extends string, IF extends Narrowable, ELSE extends Narrowable> = EndsWith<TValue, TEndsWith> extends true ? IF : EndsWith<TValue, TEndsWith> extends false ? ELSE : IF | ELSE;
2449
+
2450
+ /**
2451
+ * Makes a readonly structure mutable
2452
+ */
2453
+ type Mutable<T> = {
2454
+ -readonly [K in keyof T]: IsObject<T[K]> extends true ? Mutable<T[K]> : T[K];
2455
+ };
2456
+
2457
+ /**
2458
+ * Provides a negation of a type of the type `T` _not_ `U`.
2459
+ * ```ts
2460
+ * const foo = 42;
2461
+ * // 33
2462
+ * type NotTheMeaningOfLife = Not<33, 42>;
2463
+ * // never
2464
+ * type NotTheMeaningOfLife = Not<42, 42>;
2465
+ * ```
2466
+ *
2467
+ * Note: same as `Exclude`
2468
+ */
2469
+ type Not<T, U> = T extends U ? never : T;
2470
+
2471
+ type Digital = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
2472
+ type MakeArray<S extends string, T extends any[] = []> = S extends `${T["length"]}` ? T : MakeArray<S, [...T, 0]>;
2473
+ type Multiply10<T extends any[]> = [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T];
2474
+ /**
2475
+ * Converts a string literal to a numeric literal
2476
+ * ```ts
2477
+ * // 0
2478
+ * type Zero = Numeric<"0">;
2479
+ * // 10
2480
+ * type Ten = Numeric<"10">;
2481
+ * ```
2482
+ */
2483
+ type Numeric<S extends string, T extends any[] = []> = S extends `${infer S1}${infer S2}` ? S1 extends Digital ? Numeric<S2, [...Multiply10<T>, ...MakeArray<S1>]> : never : T["length"];
2484
+
2485
+ /**
2486
+ * **Opaque**
2487
+ *
2488
+ * Create an opaque type, which hides its internal details from the public, and
2489
+ * can only be created by being used explicitly.
2490
+ *
2491
+ * Note: taken from [type-fest](https://github.com/sindresorhus/type-fest/blob/main/source/opaque.d.ts)
2492
+ * repo.
2493
+ */
2494
+ type Opaque<Type, Token = unknown> = Type & {
2495
+ readonly __opaque__: Token;
2496
+ };
2497
+
2498
+ /**
2499
+ * **Retain<T, K>**
2500
+ *
2501
+ * Reduces the type system to just the key/values which are represented in `K`.
2502
+ * The `L` generic can largely be ignored unless you need _literal_ equality.
2503
+ *
2504
+ * ```ts
2505
+ * type Obj = { foo: 1, bar: number, baz: string };
2506
+ * // { foo: 1, bar: number }
2507
+ * type Retained = Retain<Obj, "foo" | "bar">;
2508
+ * ```
2509
+ *
2510
+ * **Note:** in essence this is the _opposite_ of `Exclude<T,K>`
2511
+ */
2512
+ type Retain<T, K extends keyof T> = Pick<T, Include<keyof T, K>>;
2513
+
2514
+ /**
2515
+ * Allows filtering down `T` to those which extend a given type `U`.
2516
+ *
2517
+ * - `T` is either a dictionary (where keys will be used to compare) or
2518
+ * a readonly sting array.
2519
+ * ```ts
2520
+ * const arr = ["foo", "bar", "baz"];
2521
+ * // "bar" | "baz"
2522
+ * type BA = Where<typeof arr, `ba${string}`>;
2523
+ * ```
2524
+ */
2525
+ type Where<T extends Record<string, any> | readonly string[], U> = T extends readonly string[] ? Include<T[number], U> : {
2526
+ [K in keyof T]: K extends U ? K : never;
2527
+ }[keyof T];
2528
+ /**
2529
+ * Allows filtering down `T` to those which extend a given type `U`.
2530
+ *
2531
+ * - `T` is either a dictionary (where keys will be used to compare) or
2532
+ * a readonly sting array.
2533
+ * ```ts
2534
+ * const arr = ["foo", "bar", "baz"];
2535
+ * // "foo"
2536
+ * type F = WhereNot<typeof arr, `ba${string}`>;
2537
+ * ```
2538
+ */
2539
+ type WhereNot<T extends Record<string, any> | readonly string[], U> = T extends readonly string[] ? Exclude<T[number], U> : {
2540
+ [K in keyof T]: K extends U ? never : K;
2541
+ }[keyof T];
2542
+
2543
+ type AppendToObject<T, U extends keyof any, V> = {
2544
+ [K in keyof T | U]: K extends keyof T ? T[K] : V;
2545
+ };
2546
+ /**
2547
+ * Appends a new Key/Value to an existing dictionary <T>
2548
+ */
2549
+ type AppendToDictionary<TDict, TKey extends string, TValue> = {
2550
+ [K in keyof TDict | TKey]: K extends keyof TDict ? TDict[K] : TValue;
2551
+ };
2552
+
2553
+ /**
2554
+ * Accepts the `true` literal or _undefined_.
2555
+ */
2556
+ type MaybeTrue = true | undefined;
2557
+ /**
2558
+ * Accepts the `false` literal or _undefined_.
2559
+ */
2560
+ type MaybeFalse = false | undefined;
2561
+
2562
+ /**
2563
+ * A conditional clause used in the application of the `ifTypeOf` utility
2564
+ */
2565
+ type ExtendsClause<N extends Narrowable, TValue extends Record<keyof TValue, N> | number | string | boolean | symbol> = <TBase extends any>(base: TBase) => TValue extends TBase ? true : false;
2566
+ /**
2567
+ * A conditional clause used in the application of the `ifTypeOf` utility
2568
+ */
2569
+ type ExtendsNarrowlyClause<N extends Narrowable, TValue extends Record<keyof TValue, N> | number | string | boolean | symbol> = <NB extends Narrowable, TBase extends Record<keyof TBase, NB> | number | string | boolean | symbol>(base: TBase) => TValue extends TBase ? true : false;
2570
+ /**
2571
+ * **TypeCondition**
2572
+ *
2573
+ * A partially applied type from the `ifTypeOf` utility where the base type has been
2574
+ * defined and we now need to express the type which is intended to extend it.
2575
+ *
2576
+ * - `extends` - compares with _wide_ types
2577
+ * - `narrowlyExtends` - compares with _narrow_ / _literal_ types
2578
+ */
2579
+ type TypeCondition<N extends Narrowable, TValue extends Record<keyof TValue, N> | number | string | boolean | symbol> = {
2580
+ extends: ExtendsClause<N, TValue>;
2581
+ narrowlyExtends: ExtendsNarrowlyClause<N, TValue>;
2582
+ };
2583
+
2584
+ /**
2585
+ * **RuleDefinition**
2586
+ *
2587
+ * A rule definition is the typing for the fluent API surface that is built up
2588
+ * with the **ruleset** utility.
2589
+ */
2590
+ type RuleDefinition<
2591
+ /** the data which will be evaluated on rule execution */
2592
+ T extends object,
2593
+ /** the optional props -- as a union type -- which must be defined per the rule */
2594
+ H extends string = "",
2595
+ /** the key/values which will be evaluated on execution (wide type) */
2596
+ E extends Partial<SameKeys<T>> = {},
2597
+ /** the key/values which will be evaluated on execution (narrow type) */
2598
+ N extends Partial<SameKeys<T>> = {}> = {
2599
+ /**
2600
+ * sets up a true/false check that a given property is defined; this
2601
+ * condition can only be applied to _optional_ properties.
2602
+ */
2603
+ has(optProp: OptionalKeys<T>): RuleDefinition<T, H & typeof optProp, E, N>;
2604
+ /**
2605
+ * Validates that a given property extends a certain value's type; comparison
2606
+ * is made assuming "wide types".
2607
+ */
2608
+ equals<K extends keyof T, V extends Pick<T, K>>(prop: K, value: V): RuleDefinition<T, H, E & Record<K, V>, N>;
2609
+ /**
2610
+ * Validates that a given property extends a certain value's type; comparison
2611
+ * is made assuming "narrow types". This is only available for props which
2612
+ * expose a
2613
+ */
2614
+ narrowlyEquals<K extends keyof T, V extends Pick<T, K>>(prop: K, value: V): RuleDefinition<T, H, E, N & Record<K, V>>;
2615
+ };
2616
+ /**
2617
+ * **DynamicRule**
2618
+ *
2619
+ * A dynamic rule allows type and runtime validation of a data structure
2620
+ * which extends a known `State`. It then returns the literal type `true`
2621
+ * or `false`.
2622
+ *
2623
+ * ```ts
2624
+ * type State = { id?: string; favorite: boolean; color: string };
2625
+ * // type-safe way to check whether optional prop is actually set
2626
+ * const rule: DynamicRule<State> = s => s
2627
+ * .has("id")
2628
+ * .equals("favorite", true)
2629
+ * .equals("color", "red");
2630
+ * ```
2631
+ */
2632
+ type DynamicRule<TState extends any, TResult extends true | false> = (rule: TypeCondition<any, TState>) => TResult;
2633
+ /**
2634
+ * **DynamicRuleSet**
2635
+ *
2636
+ * A function which accepts the agreed `TState` generic as input and returns a discrete
2637
+ * `true` or `false` value.
2638
+ */
2639
+ type DynamicRuleSet<TState extends any, TRules extends Record<string, TypeCondition<any, TState>>> = (rules: TRules) => true | false;
2640
+
2641
+ type RuntimeType<T> = {
2642
+ __kind: "type";
2643
+ type: T;
2644
+ is: TypeGuard<T>;
2645
+ };
2646
+ type RuntimeProp<P extends Readonly<PropertyKey>, T extends RuntimeType<any>> = {
2647
+ __kind: "prop";
2648
+ key: Readonly<P>;
2649
+ valueType: Readonly<T["type"]>;
2650
+ /**
2651
+ * Provides the _type_ to the type system when used with `typeof`.
2652
+ *
2653
+ * ```ts
2654
+ * const t = number();
2655
+ * // number
2656
+ * type T = typeof t.type;
2657
+ * ```
2658
+ *
2659
+ * **Note:** _the runtime system will get a string equivalent name:_
2660
+ * ```ts
2661
+ * const t = number();
2662
+ * // "number"
2663
+ * console.log(t.type);
2664
+ * ```
2665
+ */
2666
+ type: Record<P, T["type"]>;
2667
+ is: TypeGuard<Record<P, T["type"]>>;
2668
+ };
2669
+ type TypeOptions<T extends Partial<object> = {}> = {
2670
+ /** each type has a default type guard but you can override if you need to be more specific */
2671
+ typeGuard?: TypeGuard<T>;
2672
+ } & T;
2673
+
2674
+ /**
2675
+ * Validates that a given type extends another and returns `true` or `false` type
2676
+ */
2677
+ type ExpectExtends<VALUE, EXPECTED> = EXPECTED extends VALUE ? true : false;
2678
+ /**
2679
+ * Validates that a given type extends another and returns `any` or `never` as a type
2680
+ */
2681
+ type AssertExtends<VALUE, EXPECTED> = EXPECTED extends VALUE ? any : never;
2682
+ /**
2683
+ * Give a type `TValue` and a comparison type `TExtends`
2684
+ */
2685
+ type IfExtendsThen<VALUE, EXPECTED, THEN> = EXPECTED extends VALUE ? THEN : never;
2686
+
2687
+ /**
2688
+ * **ToFluent**
2689
+ *
2690
+ * Converts the typing of a dictionary of functions into the same
2691
+ * function signatures but changes the return type to be the Fluent API.
2692
+ *
2693
+ * **Note:** this utility also allows a non-fluent API surface `X` to be included as
2694
+ * part of the API surface if this is desired.
2695
+ */
2696
+ type ToFluent<T extends {
2697
+ [key: string]: (...args: any[]) => any;
2698
+ }, X extends object = {}> = {
2699
+ [K in keyof T]: (...args: Parameters<T[K]>) => ToFluent<T, X> & X;
2700
+ } & X;
2701
+ /**
2702
+ * A _pure_ Fluent API which promotes an API surface where _every_ API endpoint must be a function
2703
+ * which returns the same API surface.
2704
+ *
2705
+ * To provide value, this style of Fluent API will need to perform useful _side effects_ when functions
2706
+ * on the API surface are called as this structure does not provide any means to maintain an internal state
2707
+ * which can be returned later.
2708
+ *
2709
+ * **Note:** _if you prefer a Fluent API with means to _escape_ with an internally managed state then
2710
+ * you should prefer the use of the `FluentApi` type._
2711
+ */
2712
+ type PureFluentApi<TApi extends Record<string, (...args: any[]) => PureFluentApi<TApi, any>>, TExclude extends string = ""> = {
2713
+ [P in keyof TApi]: (...args: Parameters<TApi[P]>) => PureFluentApi<Omit<TApi, TExclude>>;
2714
+ };
2715
+
2716
+ export { AfterFirst, AllCaps, Alpha, AlphaNumeric, AnyFunction, Api, ApiFunction, ApiValue, AppendToDictionary, AppendToObject, ArrConcat, Array$1 as Array, ArrayConverter, AsArray, AsFinalizedConfig, AssertExtends, Box, BoxValue, BoxedFnParams, BoxedReturn, Bracket, Break, CamelCase, CapitalizeWords, Cardinality, Cardinality0, Cardinality1, CardinalityExplicit, CardinalityFilter0, CardinalityFilter1, CardinalityIn, CardinalityInput, CardinalityNode, CardinalityOut, CardinalityTuple, ClosingBracket, Condition, ConditionFilter, Configurator, ConfiguredMap, Constructor, Contains, DEFAULT_MANY_TO_ONE_MAPPING, DEFAULT_ONE_TO_MANY_MAPPING, DEFAULT_ONE_TO_ONE_MAPPING, DashToSnake, DashUppercase, Dasherize, DecomposeMapConfig, DefaultManyToOneMapping, DefaultOneToManyMapping, DefaultOneToOneMapping, DefinePropertiesApi, DictArrApi, DictArray, DictArrayFilterCallback, DictArrayKv, DictChangeValue, DictFromKv, DictKvTuple, DictPartialApplication, DictPrependWithFn, DictReturnValues, DictionaryWithoutValue, DomainName, DynamicRule, DynamicRuleSet, Email, EndsWith, EnsureLeading, EnsureTrailing, EnumValues, ExpandRecursively, ExpectExtends, ExplicitFunction, Extends, FilterContains, FilterDefn, FilterEnds, FilterEquals, FilterFn, FilterGreaterThan, FilterIs, FilterLessThan, FilterNotEqual, FilterStarts, FilterTuple, FinalReturn, FinalizedMapConfig, First, FirstKey, FirstKeyValue, FirstOfEach, FirstOrUndefined, FirstString, FluentConfigurator, FluentFunction, FnShape, FromDictArray, FullyQualifiedUrl, FunctionType, GeneralDictionary, Get, HasParameters, HasUppercase, HybridFunction, IConfigurator, IFluentConfigurator, If, IfArray, IfBooleanLiteral, IfEndsWith, IfExtends, IfExtendsThen, IfFalse, IfLiteral, IfNumericLiteral, IfObject, IfOptionalLiteral, IfReadonlyArray, IfScalar, IfStartsWith, IfStringLiteral, IfTrue, IfUndefined, Include, Includes, IntersectingKeys, Ipv4, IsArray, IsBoolean, IsBooleanLiteral, IsCapitalized, IsEqual, IsFalse, IsFunction, IsLiteral, IsNull, IsNumber, IsNumericLiteral, IsObject, IsOptionalLiteral, IsReadonlyArray, IsScalar, IsStringLiteral, IsTrue, IsUndefined, KebabCase, KeyValue, KeyedRecord, Keys, KeysWithValue, KvFrom, KvTuple, LastInUnion, LeftWhitespace, Length, LogicFunction, LogicalCombinator, LowerAllCaps, LowerAlpha, ManyToMany, ManyToOne, ManyToZero, MapCard, MapCardinality, MapCardinalityFrom, MapCardinalityIllustrated, MapConfig, MapFn, MapFnInput, MapFnOutput, MapIR, MapInput, MapInputFrom, MapOR, MapOutput, MapOutputFrom, MapTo, Mapper, MapperApi, MaybeFalse, MaybeTrue, Mutable, MutableProps, NarrowBox, Narrowable, NarrowlyContains, NetworkProtocol, NonAlpha, NonNumericKeys, NonStringKeys, Not, NotEqual, NotFilter, Numeric, NumericFilter, NumericKeys, NumericString, ObjectType, OneToMany, OneToOne, OneToZero, Opaque, OpeningBracket, OptRequired, OptionalKeys, OptionalProps, Or, Parenthesis, PascalCase, Pluralize, PrivateKey, PrivateKeys, PublicKeys, Punctuation, PureFluentApi, RelativeUrl, Replace, RequireProps, RequiredKeys, RequiredProps, Retain, RightWhitespace, RuleDefinition, RuntimeProp, RuntimeType, SameKeys, SecondOfEach, SimpleFunction, SimplifyObject, SnakeCase, SpecialCharacters, Split, StartsWith, StringDelimiter, StringFilter, StringKeys, StringLength, StripLeading, StripTrailing, Suggest, SuggestNumeric, ToFluent, Transformer, Trim, TrimLeft, TrimRight, TupleToUnion, Type, TypeApi, TypeDefault, TypeDefinition, TypeGuard, TypeOptions, Unbox, UndefinedArrayIsUnknown, UndefinedTreatment, UndefinedValue, UnionToIntersection, UnionToTuple, UniqueDictionary, UniqueForProp, Uniqueness, UnwrapNot, UpperAlpha, UrlBuilder, VariableName, Where, WhereNot, Whitespace, Widen, WithNumericKeys, WithStringKeys, WithValue, ZeroToMany, ZeroToOne, ZeroToZero, ZipCode, and, api, arrayToKeyLookup, arrayToObject, asArray, box, boxDictionaryValues, condition, createConverter, createFnWithProps, defineProperties, defineType, dictArr, dictToKv, dictionaryTransform, ensureLeading, ensureTrailing, entries, filter, filterDictArray, fnWithProps, groupBy, idLiteral, idTypeGuard, identity, ifArray, ifArrayPartial, ifBoolean, ifDefined, ifFalse, ifNull, ifNumber, ifObject, ifSameType, ifString, ifTrue, ifUndefined, isArray, isBoolean, isBox, isFalse, isFunction, isNotFilter, isNull, isNumber, isNumericFilter, isObject, isString, isSymbol, isTrue, isType, isUndefined, keys, kindLiteral, kv, kvToDict, literal, mapTo, mapToDict, mapToFn, mapValues, nameLiteral, not, or, readonlyFnWithProps, ruleSet, strArrayToDict, stripTrailing, type, typeApi, unbox, wide, withValue };