inferred-types 0.35.0 → 0.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -34
- package/dist/index.d.ts +1812 -1656
- package/dist/index.mjs +95 -26
- package/package.json +12 -11
- package/src/runtime/combinators/filter.ts +0 -1
- package/src/runtime/lists/asArray.ts +8 -4
- package/src/runtime/lists/createConverter.ts +62 -0
- package/src/runtime/lists/index.ts +1 -0
- package/src/runtime/literals/box.ts +41 -20
- package/src/runtime/literals/ensureLeading.ts +17 -0
- package/src/runtime/literals/ensureTrailing.ts +17 -0
- package/src/runtime/literals/index.ts +4 -2
- package/src/runtime/literals/pathJoin.ts +22 -7
- package/src/runtime/literals/{stripStarting.ts → stripLeading.ts} +4 -4
- package/src/runtime/literals/stripTrailing.ts +15 -0
- package/src/runtime/literals/wide.ts +13 -0
- package/src/runtime/type-checks/ifSameType.ts +20 -0
- package/src/runtime/type-checks/index.ts +1 -0
- package/src/runtime/type-checks/isBoolean.ts +2 -1
- package/src/runtime/type-checks/isFunction.ts +2 -4
- package/src/runtime/type-checks/isObject.ts +10 -2
- package/src/runtime/type-checks/isString.ts +1 -1
- package/src/runtime/type-checks/isUndefined.ts +8 -0
- package/src/types/alphabetic/EnsureLeading.ts +24 -0
- package/src/types/alphabetic/EnsureTrailing.ts +24 -0
- package/src/types/alphabetic/PathJoin.ts +43 -31
- package/src/types/alphabetic/{StripStarting.ts → StripLeading.ts} +1 -1
- package/src/types/alphabetic/{StripEnding.ts → StripTrailing.ts} +1 -1
- package/src/types/alphabetic/index.ts +5 -2
- package/src/types/boolean-logic/HasParameters.ts +21 -0
- package/src/types/boolean-logic/array.ts +2 -2
- package/src/types/boolean-logic/boolean.ts +1 -1
- package/src/types/boolean-logic/equivalency.ts +2 -2
- package/src/types/boolean-logic/index.ts +1 -0
- package/src/types/dictionary/props.ts +5 -0
- package/src/types/lists/ConvertAndMap.ts +151 -0
- package/src/types/type-conversion/Widen.ts +15 -0
- package/tests/boolean-logic/HasParameters.ts +29 -0
- package/tests/lists/asArray.test.ts +19 -1
- package/tests/literals/EnsureStripLeadingTrailing.test.ts +79 -0
- package/tests/literals/PathJoin.test.ts +44 -37
- package/tests/literals/box.test.ts +31 -23
- package/tests/runtime/if-is.spec.ts +66 -5
- package/tests/runtime/map-and-convert.test.ts +31 -0
- package/dist/index.js +0 -868
- package/src/runtime/literals/stripEnding.ts +0 -9
|
@@ -27,7 +27,7 @@ export function isString<T>(i: T) {
|
|
|
27
27
|
*/
|
|
28
28
|
export function ifString<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(
|
|
29
29
|
val: T,
|
|
30
|
-
ifVal: IF,
|
|
30
|
+
ifVal: <E extends string>(t: E & T) => IF,
|
|
31
31
|
elseVal: ELSE
|
|
32
32
|
) {
|
|
33
33
|
return (isString(val) ? ifVal : elseVal) as IfString<T, IF, ELSE>;
|
|
@@ -23,3 +23,11 @@ export function ifUndefined<T extends Narrowable, IF extends Narrowable, ELSE ex
|
|
|
23
23
|
) {
|
|
24
24
|
return (isUndefined(val) ? ifVal : elseVal) as IsUndefined<T> extends true ? IF : ELSE;
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
export function ifDefined<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(
|
|
28
|
+
val: T,
|
|
29
|
+
ifVal: <V extends Exclude<T, undefined>>(v: V) => IF,
|
|
30
|
+
elseVal: ELSE
|
|
31
|
+
) {
|
|
32
|
+
return (isUndefined(val) ? ifVal : elseVal) as IsUndefined<T> extends true ? IF : ELSE;
|
|
33
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { IfLiteral } from "../boolean-logic/IsLiteral";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* **EnsureLeading**`<T, U>`
|
|
5
|
+
*
|
|
6
|
+
* Will ensure that `T` ends with the _substring_ `U` when
|
|
7
|
+
* both are string literals.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* type T = " World";
|
|
11
|
+
* type U = "Hello";
|
|
12
|
+
* // "Hello World"
|
|
13
|
+
* type R = EnsureLeading<T,U>;
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export type EnsureLeading<T extends string, U extends string> = IfLiteral<
|
|
17
|
+
// can only operate on literal strings
|
|
18
|
+
T,
|
|
19
|
+
// this path represents successful strip opp
|
|
20
|
+
// but we must never accept `U` being wide
|
|
21
|
+
string extends U ? never : T extends `${U}${string}` ? T : `${U}${T}`,
|
|
22
|
+
// here we must stay wide
|
|
23
|
+
string
|
|
24
|
+
>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { IfLiteral } from "../boolean-logic/IsLiteral";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* **EnsureTrailing**`<T, U>`
|
|
5
|
+
*
|
|
6
|
+
* Will ensure that `T` ends with the substring `U` when
|
|
7
|
+
* both are string literals.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* type T = "Hello";
|
|
11
|
+
* type U = " World";
|
|
12
|
+
* // "Hello World"
|
|
13
|
+
* type R = EnsureTrailing<T,U>;
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export type EnsureTrailing<T extends string, U extends string> = IfLiteral<
|
|
17
|
+
// can only operate on literal strings
|
|
18
|
+
T,
|
|
19
|
+
// this path represents successful strip opp
|
|
20
|
+
// but we must never accept `U` being wide
|
|
21
|
+
string extends U ? never : T extends `${string}${U}` ? T : `${T}${U}`,
|
|
22
|
+
// here we must stay wide
|
|
23
|
+
string
|
|
24
|
+
>;
|
|
@@ -1,40 +1,52 @@
|
|
|
1
1
|
import { IfLiteral } from "../boolean-logic";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { AfterFirst, First } from "../lists";
|
|
3
|
+
import { StripTrailing } from "./StripTrailing";
|
|
4
|
+
import { StripLeading } from "./StripLeading";
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* **PathJoin**`<T,U>`
|
|
6
8
|
*
|
|
7
|
-
* Type utility
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* Type utility meant to bring 2 or more "path" strings together into
|
|
10
|
+
* a valid "path". Where a "path" is represented as nothing more than
|
|
11
|
+
* string characters delimited by a Posix `\` character.
|
|
10
12
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* **Note:** that in the case that both `T` and `U` are wide,
|
|
17
|
-
* we opt to type the result as just a _string_ rather than
|
|
18
|
-
* `${string}/${string}` which might be more precise 99% of
|
|
19
|
-
* the time but where `T` is an empty string there actually
|
|
20
|
-
* is no guarantee of a `/` character. Similarly we must
|
|
21
|
-
* type the case where `U` is narrow but `T` is wide as
|
|
22
|
-
* being `${string}${U}` instead of `${string}/${U}`.
|
|
13
|
+
* Note that the first part of the path will retain it's `\` if present
|
|
14
|
+
* and the last one will preserve it's `\` character if present. You can
|
|
15
|
+
* combine this utility with `EnsureTrailing<T>`, `StripTrailing<T>`,
|
|
16
|
+
* `EnsureStarting<T>`, and `StripStarting<T>` to further shape
|
|
17
|
+
* the type.
|
|
23
18
|
*/
|
|
24
19
|
export type PathJoin<
|
|
25
20
|
// leading string
|
|
26
21
|
T extends string,
|
|
27
|
-
// trailing string
|
|
28
|
-
U extends string
|
|
29
|
-
> =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
22
|
+
// trailing string or strings
|
|
23
|
+
U extends string | readonly string[]
|
|
24
|
+
> = U extends readonly string[]
|
|
25
|
+
? // eslint-disable-next-line no-use-before-define
|
|
26
|
+
PathMultiJoin<PathJoin<T, "">, [...U]>
|
|
27
|
+
: U extends string
|
|
28
|
+
? IfLiteral<
|
|
29
|
+
T,
|
|
30
|
+
// Literal T guaranteed
|
|
31
|
+
IfLiteral<
|
|
32
|
+
// conditional
|
|
33
|
+
U,
|
|
34
|
+
`${StripTrailing<T, "/">}/${StripLeading<U, "/">}`,
|
|
35
|
+
`${StripTrailing<T, "/">}/${string}`
|
|
36
|
+
>,
|
|
37
|
+
// wide `T` encountered
|
|
38
|
+
IfLiteral<U, `${string}${U}`, string>
|
|
39
|
+
>
|
|
40
|
+
: never;
|
|
41
|
+
|
|
42
|
+
type PathMultiJoin<
|
|
43
|
+
TProcessed extends string,
|
|
44
|
+
TRemaining extends readonly string[]
|
|
45
|
+
> = [] extends TRemaining
|
|
46
|
+
? TProcessed
|
|
47
|
+
: PathMultiJoin<
|
|
48
|
+
// add to the TProcessed string
|
|
49
|
+
PathJoin<TProcessed, First<TRemaining>>,
|
|
50
|
+
// remaining elements after extracting head element
|
|
51
|
+
AfterFirst<TRemaining>
|
|
52
|
+
>;
|
|
@@ -12,7 +12,7 @@ import { IfLiteral } from "../boolean-logic/IsLiteral";
|
|
|
12
12
|
* type R = StripStarting<T,U>;
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export type
|
|
15
|
+
export type StripLeading<T extends string, U extends string> = IfLiteral<
|
|
16
16
|
// can only operate on literal strings
|
|
17
17
|
T,
|
|
18
18
|
// this path represents successful strip opp
|
|
@@ -12,7 +12,7 @@ import { IfLiteral } from "../boolean-logic/IsLiteral";
|
|
|
12
12
|
* type R = StripEnding<T,U>;
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export type
|
|
15
|
+
export type StripTrailing<T extends string, U extends string> = IfLiteral<
|
|
16
16
|
// can only operate on literal strings
|
|
17
17
|
T,
|
|
18
18
|
// this path represents successful strip opp
|
|
@@ -12,14 +12,17 @@ export * from "./DashUppercase";
|
|
|
12
12
|
export * from "./Cardinality";
|
|
13
13
|
export * from "./Dasherize";
|
|
14
14
|
export * from "./HasUppercase";
|
|
15
|
+
export * from "./EnsureLeading";
|
|
16
|
+
export * from "./EnsureTrailing";
|
|
15
17
|
export * from "./IsCapitalized";
|
|
16
18
|
export * from "./KebabCase";
|
|
17
19
|
export * from "./LowerAllCaps";
|
|
18
20
|
export * from "./PascalCase";
|
|
21
|
+
export * from "./PathJoin";
|
|
19
22
|
export * from "./Pluralize";
|
|
20
23
|
export * from "./SnakeCase";
|
|
21
|
-
export * from "./
|
|
22
|
-
export * from "./
|
|
24
|
+
export * from "./StripLeading";
|
|
25
|
+
export * from "./StripTrailing";
|
|
23
26
|
export * from "./alpha-characters";
|
|
24
27
|
export * from "./Url";
|
|
25
28
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AnyFunction } from "src/runtime";
|
|
2
|
+
import { Length } from "../Length";
|
|
3
|
+
import { Narrowable } from "../Narrowable";
|
|
4
|
+
import { IsEqual } from "./equivalency";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* **HasParameters**`<T>`
|
|
8
|
+
*
|
|
9
|
+
* Type utility which detects if `T` is both a function and whether that
|
|
10
|
+
* function has at least one type parameter.
|
|
11
|
+
* ```ts
|
|
12
|
+
* const fn = (foo: string) => `${foo}bar`;
|
|
13
|
+
* // true
|
|
14
|
+
* type P = HasParameters<typeof fn>;
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export type HasParameters<T extends Narrowable> = T extends AnyFunction
|
|
18
|
+
? IsEqual<Length<Parameters<T>>, 0> extends true
|
|
19
|
+
? false
|
|
20
|
+
: true
|
|
21
|
+
: false;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IsEqual } from "./equivalency";
|
|
2
2
|
import { AfterFirst, First } from "../lists";
|
|
3
3
|
import { Narrowable } from "../Narrowable";
|
|
4
4
|
|
|
@@ -47,7 +47,7 @@ export type Contains<T extends Narrowable, A extends readonly any[]> = First<A>
|
|
|
47
47
|
* `true` if `T` _extends_ any element in `A` making it match widely against `A`. If you
|
|
48
48
|
* prefer a wider match you can use `Contains<T,A>` instead.
|
|
49
49
|
*/
|
|
50
|
-
export type NarrowlyContains<T extends Narrowable, A extends readonly any[]> =
|
|
50
|
+
export type NarrowlyContains<T extends Narrowable, A extends readonly any[]> = IsEqual<
|
|
51
51
|
First<A>,
|
|
52
52
|
T
|
|
53
53
|
> extends true
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Type utility which tests whether two types -- `X` and `Y` -- are exactly the same type
|
|
5
5
|
*/
|
|
6
|
-
export type
|
|
6
|
+
export type IsEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
|
|
7
7
|
? true
|
|
8
8
|
: false;
|
|
9
9
|
|
|
@@ -12,4 +12,4 @@ export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T exte
|
|
|
12
12
|
*
|
|
13
13
|
* Type utility which tests whether two types -- `X` and `Y` -- are _not_ exactly the same type
|
|
14
14
|
*/
|
|
15
|
-
export type NotEqual<X, Y> = true extends
|
|
15
|
+
export type NotEqual<X, Y> = true extends IsEqual<X, Y> ? false : true;
|
|
@@ -128,6 +128,11 @@ export type WithValue<
|
|
|
128
128
|
: // Exclude using E
|
|
129
129
|
Omit<Pick<T, KeysWithValue<W, T>>, KeysWithValue<E, T>>;
|
|
130
130
|
|
|
131
|
+
export type DictionaryWithoutValue<TDict extends object, TWithoutValue> = Omit<
|
|
132
|
+
TDict,
|
|
133
|
+
KeysWithValue<TWithoutValue, TDict>
|
|
134
|
+
>;
|
|
135
|
+
|
|
131
136
|
/**
|
|
132
137
|
* Reduces an object to only the key/value pairs where the key is a
|
|
133
138
|
* string.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { TupleToUnion, UnionToTuple } from "../type-conversion";
|
|
2
|
+
import { Narrowable } from "../Narrowable";
|
|
3
|
+
import { First } from "./First";
|
|
4
|
+
import { AfterFirst } from "./AfterFirst";
|
|
5
|
+
import { Keys } from "../Keys";
|
|
6
|
+
|
|
7
|
+
import { DictionaryWithoutValue } from "../dictionary/props";
|
|
8
|
+
|
|
9
|
+
// [Mapped Tuple Types](https://github.com/Microsoft/TypeScript/issues/25947)
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The basic shape of a `Converter`
|
|
13
|
+
*/
|
|
14
|
+
export type ConverterShape<
|
|
15
|
+
S extends Narrowable,
|
|
16
|
+
N extends Narrowable,
|
|
17
|
+
B extends Narrowable,
|
|
18
|
+
O extends Narrowable
|
|
19
|
+
> = {
|
|
20
|
+
string: <T extends string>(v: T) => S;
|
|
21
|
+
number: <T extends number>(v: T) => N;
|
|
22
|
+
boolean: <T extends boolean>(v: T) => B;
|
|
23
|
+
object: <T extends Record<string, any>>(v: T) => O;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type ConverterKeys<S, N, B, O> = UnionToTuple<
|
|
27
|
+
Keys<
|
|
28
|
+
DictionaryWithoutValue<
|
|
29
|
+
{
|
|
30
|
+
string: S;
|
|
31
|
+
number: N;
|
|
32
|
+
boolean: B;
|
|
33
|
+
object: O;
|
|
34
|
+
},
|
|
35
|
+
undefined
|
|
36
|
+
>
|
|
37
|
+
>
|
|
38
|
+
>;
|
|
39
|
+
|
|
40
|
+
type ConverterInputType<T extends string> = T extends "string"
|
|
41
|
+
? string
|
|
42
|
+
: T extends "number"
|
|
43
|
+
? number
|
|
44
|
+
: T extends "boolean"
|
|
45
|
+
? boolean
|
|
46
|
+
: T extends "object"
|
|
47
|
+
? Record<string, any>
|
|
48
|
+
: unknown;
|
|
49
|
+
|
|
50
|
+
type ConverterInputUnion<
|
|
51
|
+
TConverted extends readonly any[],
|
|
52
|
+
TRemaining extends readonly string[]
|
|
53
|
+
> = [] extends TRemaining
|
|
54
|
+
? // we're done iterating
|
|
55
|
+
TConverted
|
|
56
|
+
: // recurse
|
|
57
|
+
ConverterInputUnion<
|
|
58
|
+
[...TConverted, ConverterInputType<First<TRemaining>>],
|
|
59
|
+
AfterFirst<TRemaining>
|
|
60
|
+
>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* **AvailableConverters**
|
|
64
|
+
*
|
|
65
|
+
* Type utility which will produce the correct union type for a "converter"
|
|
66
|
+
*/
|
|
67
|
+
export type AvailableConverters<S, N, B, O> = ConverterKeys<S, N, B, O> extends readonly string[]
|
|
68
|
+
? TupleToUnion<ConverterInputUnion<[], ConverterKeys<S, N, B, O>>>
|
|
69
|
+
: never;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* **Converter**
|
|
73
|
+
*
|
|
74
|
+
* A type converter coming from the `createConverter()` utility. It receives
|
|
75
|
+
* one or more broad types (e.g., number, string, etc.) -- what it can take
|
|
76
|
+
* is based on what is configured -- and then converts based on the value
|
|
77
|
+
* passed in.
|
|
78
|
+
*
|
|
79
|
+
* The primary goal is to preserve as many _narrow_ types as possible in this process.
|
|
80
|
+
*/
|
|
81
|
+
export type Converter<
|
|
82
|
+
S extends Narrowable,
|
|
83
|
+
N extends Narrowable,
|
|
84
|
+
B extends Narrowable,
|
|
85
|
+
O extends Narrowable
|
|
86
|
+
> = <T extends AvailableConverters<S, N, B, O>>(input: T) => ConverterShape<S, N, B, O>;
|
|
87
|
+
|
|
88
|
+
export type Conversion<TInput extends Narrowable, TOutput extends Narrowable> = <T extends TInput>(
|
|
89
|
+
input: T
|
|
90
|
+
) => TOutput;
|
|
91
|
+
|
|
92
|
+
export type ConverterCoverage = "string" | "number" | "boolean" | "object";
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Extracts the coverage provided by a `StrongMap` as a Tuple
|
|
96
|
+
*/
|
|
97
|
+
export type MapCoverage<T extends StrongMap<ConverterCoverage>> = T extends StrongMap<
|
|
98
|
+
infer Coverage
|
|
99
|
+
>
|
|
100
|
+
? UnionToTuple<Coverage>
|
|
101
|
+
: never;
|
|
102
|
+
|
|
103
|
+
export type StrongMapTypes<K extends readonly any[]> = [] extends K
|
|
104
|
+
? never
|
|
105
|
+
: TupleToUnion<
|
|
106
|
+
[
|
|
107
|
+
First<K> extends "string"
|
|
108
|
+
? TupleToUnion<[string, ...UnionToTuple<StrongMapTypes<AfterFirst<K>>>]>
|
|
109
|
+
: First<K> extends "number"
|
|
110
|
+
? TupleToUnion<[number, ...UnionToTuple<StrongMapTypes<AfterFirst<K>>>]>
|
|
111
|
+
: First<K> extends "boolean"
|
|
112
|
+
? TupleToUnion<[boolean, ...UnionToTuple<StrongMapTypes<AfterFirst<K>>>]>
|
|
113
|
+
: First<K> extends "object"
|
|
114
|
+
? TupleToUnion<[Record<string, any>, ...UnionToTuple<StrongMapTypes<AfterFirst<K>>>]>
|
|
115
|
+
: never,
|
|
116
|
+
...UnionToTuple<StrongMapTypes<AfterFirst<K>>>
|
|
117
|
+
]
|
|
118
|
+
>;
|
|
119
|
+
|
|
120
|
+
export type StrongMap<TDefined = ConverterCoverage> = {
|
|
121
|
+
string: TDefined extends "string" ? <T extends string, R extends any>(v: T) => R : never;
|
|
122
|
+
number: TDefined extends "number" ? <T extends number, R extends any>(v: T) => R : never;
|
|
123
|
+
boolean: TDefined extends "boolean" ? <T extends boolean, R extends any>(v: T) => R : never;
|
|
124
|
+
object: TDefined extends "object"
|
|
125
|
+
? <T extends Record<string, any>, R extends any>(v: T) => R
|
|
126
|
+
: never;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export type StrongMapTransformer<M extends StrongMap> = <
|
|
130
|
+
T extends readonly StrongMapTypes<MapCoverage<M>>[]
|
|
131
|
+
>(
|
|
132
|
+
tuple: T
|
|
133
|
+
) => {
|
|
134
|
+
[K in keyof T]: T[K] extends string
|
|
135
|
+
? M["string"] extends (...args: any[]) => any
|
|
136
|
+
? ReturnType<M["string"]>
|
|
137
|
+
: never
|
|
138
|
+
: T[K] extends number
|
|
139
|
+
? M["number"] extends (...args: any[]) => any
|
|
140
|
+
? ReturnType<M["number"]>
|
|
141
|
+
: never
|
|
142
|
+
: T[K] extends boolean
|
|
143
|
+
? M["boolean"] extends (...args: any[]) => any
|
|
144
|
+
? ReturnType<M["boolean"]>
|
|
145
|
+
: never
|
|
146
|
+
: T[K] extends Record<string, any>
|
|
147
|
+
? M["object"] extends (...args: any[]) => any
|
|
148
|
+
? ReturnType<M["object"]>
|
|
149
|
+
: never
|
|
150
|
+
: never;
|
|
151
|
+
}[keyof T];
|
|
@@ -1,7 +1,22 @@
|
|
|
1
|
+
import { AnyFunction } from "src/runtime";
|
|
2
|
+
import { TupleToUnion } from "./TupleToUnion";
|
|
3
|
+
|
|
1
4
|
export type Widen<T> = T extends string
|
|
2
5
|
? string
|
|
3
6
|
: T extends number
|
|
4
7
|
? number
|
|
5
8
|
: T extends boolean
|
|
6
9
|
? boolean
|
|
10
|
+
: T extends readonly string[]
|
|
11
|
+
? string[]
|
|
12
|
+
: T extends readonly number[]
|
|
13
|
+
? number[]
|
|
14
|
+
: T extends readonly boolean[]
|
|
15
|
+
? boolean[]
|
|
16
|
+
: T extends readonly AnyFunction[]
|
|
17
|
+
? AnyFunction[]
|
|
18
|
+
: T extends readonly any[]
|
|
19
|
+
? TupleToUnion<T>[]
|
|
20
|
+
: T extends {}
|
|
21
|
+
? {}
|
|
7
22
|
: T;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Equal, Expect } from "@type-challenges/utils";
|
|
2
|
+
import { HasParameters } from "src/types";
|
|
3
|
+
import { describe, it } from "vitest";
|
|
4
|
+
|
|
5
|
+
// Note: type tests fail visible inspection but pass from Vitest
|
|
6
|
+
// standpoint so always be sure to run `tsc --noEmit` over your test files to
|
|
7
|
+
// gain validation that no new type vulnerabilities have cropped up.
|
|
8
|
+
|
|
9
|
+
describe("HasParameters<T>", () => {
|
|
10
|
+
it("happy path", () => {
|
|
11
|
+
const fn1 = (foo: string) => `${foo}bar`;
|
|
12
|
+
const fn2 = (foo: string) => `${foo}bar` as const;
|
|
13
|
+
const fn3 = () => `hello world`;
|
|
14
|
+
const fn4 = () => `hello world` as const;
|
|
15
|
+
const fn5 = (r: string, g: string, b: string) => `${r},${g},${b}` as const;
|
|
16
|
+
|
|
17
|
+
type cases = [
|
|
18
|
+
// single
|
|
19
|
+
Expect<Equal<HasParameters<typeof fn1>, true>>,
|
|
20
|
+
Expect<Equal<HasParameters<typeof fn2>, true>>,
|
|
21
|
+
// none
|
|
22
|
+
Expect<Equal<HasParameters<typeof fn3>, false>>,
|
|
23
|
+
Expect<Equal<HasParameters<typeof fn4>, false>>,
|
|
24
|
+
// multiple
|
|
25
|
+
Expect<Equal<HasParameters<typeof fn5>, true>>
|
|
26
|
+
];
|
|
27
|
+
const cases: cases = [true, true, true, true, true];
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { asArray } from "src/runtime";
|
|
2
|
+
import { AsArray, asArray } from "src/runtime";
|
|
3
3
|
import { Equal, Expect } from "@type-challenges/utils";
|
|
4
4
|
|
|
5
|
+
describe("AsArray<T>", () => {
|
|
6
|
+
it("happy path", () => {
|
|
7
|
+
type T1 = AsArray<4>;
|
|
8
|
+
type T2 = AsArray<4, true>;
|
|
9
|
+
type T3 = AsArray<[4, 5, 6]>;
|
|
10
|
+
type T4 = AsArray<[4, 5, 6], true>;
|
|
11
|
+
|
|
12
|
+
type cases = [
|
|
13
|
+
//
|
|
14
|
+
Expect<Equal<T1, 4[]>>,
|
|
15
|
+
Expect<Equal<T2, number[]>>,
|
|
16
|
+
Expect<Equal<T3, [4, 5, 6]>>,
|
|
17
|
+
Expect<Equal<T4, number[]>>
|
|
18
|
+
];
|
|
19
|
+
const cases: cases = [true, true, true, true];
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
5
23
|
describe("asArray() function", () => {
|
|
6
24
|
it("non-array is returned as an array", () => {
|
|
7
25
|
const i = "a";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Equal, Expect } from "@type-challenges/utils";
|
|
2
|
+
import { ensureLeading } from "src/runtime/literals/ensureLeading";
|
|
3
|
+
import { ensureTrailing } from "src/runtime/literals/ensureTrailing";
|
|
4
|
+
import { stripLeading } from "src/runtime/literals/stripLeading";
|
|
5
|
+
import { stripTrailing } from "src/runtime/literals/stripTrailing";
|
|
6
|
+
import { EnsureLeading, EnsureTrailing, StripLeading, StripTrailing } from "src/types/alphabetic";
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
|
|
9
|
+
// Note: while type tests clearly fail visible inspection, they pass from Vitest
|
|
10
|
+
// standpoint so always be sure to run `tsc --noEmit` over your test files to
|
|
11
|
+
// gain validation that no new type vulnerabilities have cropped up.
|
|
12
|
+
|
|
13
|
+
describe("EnsureLeading", () => {
|
|
14
|
+
it("EnsureLeading<T,U>", () => {
|
|
15
|
+
type T1 = EnsureLeading<"bar", "foo">;
|
|
16
|
+
type T2 = EnsureLeading<"foobar", "foo">;
|
|
17
|
+
|
|
18
|
+
type cases = [Expect<Equal<T1, "foobar">>, Expect<Equal<T2, "foobar">>];
|
|
19
|
+
const cases: cases = [true, true];
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("ensureLeading()", () => {
|
|
23
|
+
const t1 = ensureLeading("bar", "foo");
|
|
24
|
+
const t2 = ensureLeading("foobar", "foo");
|
|
25
|
+
expect(t1).toBe("foobar");
|
|
26
|
+
expect(t2).toBe("foobar");
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("EnsureTrailing", () => {
|
|
31
|
+
it("EnsureTrailing<T,U>", () => {
|
|
32
|
+
type T1 = EnsureTrailing<"foo", "bar">;
|
|
33
|
+
type T2 = EnsureTrailing<"foobar", "bar">;
|
|
34
|
+
|
|
35
|
+
type cases = [Expect<Equal<T1, "foobar">>, Expect<Equal<T2, "foobar">>];
|
|
36
|
+
const cases: cases = [true, true];
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("ensureTrailing()", () => {
|
|
40
|
+
const t1 = ensureTrailing("foo", "bar");
|
|
41
|
+
const t2 = ensureTrailing("foobar", "bar");
|
|
42
|
+
expect(t1).toBe("foobar");
|
|
43
|
+
expect(t2).toBe("foobar");
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("StripLeading", () => {
|
|
48
|
+
it("StripLeading<T,U>", () => {
|
|
49
|
+
type T1 = StripLeading<"foobar", "foo">;
|
|
50
|
+
type T2 = StripLeading<"bar", "foo">;
|
|
51
|
+
|
|
52
|
+
type cases = [Expect<Equal<T1, "bar">>, Expect<Equal<T2, "bar">>];
|
|
53
|
+
const cases: cases = [true, true];
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("stripLeading()", () => {
|
|
57
|
+
const t1 = stripLeading("foobar", "foo");
|
|
58
|
+
const t2 = stripLeading("bar", "foo");
|
|
59
|
+
expect(t1).toBe("bar");
|
|
60
|
+
expect(t2).toBe("bar");
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("StripTrailing", () => {
|
|
65
|
+
it("StripTrailing<T,U>", () => {
|
|
66
|
+
type T1 = StripTrailing<"foobar", "bar">;
|
|
67
|
+
type T2 = StripTrailing<"foo", "bar">;
|
|
68
|
+
|
|
69
|
+
type cases = [Expect<Equal<T1, "foo">>, Expect<Equal<T2, "foo">>];
|
|
70
|
+
const cases: cases = [true, true];
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("stripTrailing()", () => {
|
|
74
|
+
const t1 = stripTrailing("foobar", "bar");
|
|
75
|
+
const t2 = stripTrailing("foo", "bar");
|
|
76
|
+
expect(t1).toBe("foo");
|
|
77
|
+
expect(t2).toBe("foo");
|
|
78
|
+
});
|
|
79
|
+
});
|