type-fest 4.35.0 → 4.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/source/array-slice.d.ts +1 -1
- package/source/array-splice.d.ts +3 -1
- package/source/camel-cased-properties-deep.d.ts +6 -11
- package/source/delimiter-case.d.ts +31 -57
- package/source/internal/numeric.d.ts +27 -0
- package/source/kebab-case.d.ts +6 -1
- package/source/paths.d.ts +1 -7
- package/source/replace.d.ts +17 -5
- package/source/screaming-snake-case.d.ts +8 -17
- package/source/snake-case.d.ts +6 -1
- package/source/split.d.ts +60 -6
- package/source/subtract.d.ts +52 -39
- package/source/sum.d.ts +47 -39
- package/source/tsconfig-json.d.ts +18 -2
- package/source/words.d.ts +64 -13
package/package.json
CHANGED
package/source/array-slice.d.ts
CHANGED
|
@@ -91,7 +91,7 @@ type ArraySliceHelper<
|
|
|
91
91
|
? Sum<ArrayLength, Start> extends infer AddResult extends number
|
|
92
92
|
? number extends AddResult // (ArrayLength + Start) < 0
|
|
93
93
|
? 0
|
|
94
|
-
: AddResult
|
|
94
|
+
: GreaterThan<AddResult, 0> extends true ? AddResult : 0
|
|
95
95
|
: never
|
|
96
96
|
: Start,
|
|
97
97
|
PositiveE extends number = IsNegative<End> extends true ? Sum<ArrayLength, End> : End,
|
package/source/array-splice.d.ts
CHANGED
|
@@ -21,7 +21,9 @@ The implementation of `SplitArrayByIndex` for variable length arrays.
|
|
|
21
21
|
type SplitVariableArrayByIndex<T extends UnknownArray,
|
|
22
22
|
SplitIndex extends number,
|
|
23
23
|
T1 = Subtract<SplitIndex, StaticPartOfArray<T>['length']>,
|
|
24
|
-
T2 = T1 extends number
|
|
24
|
+
T2 = T1 extends number
|
|
25
|
+
? BuildTuple<GreaterThanOrEqual<T1, 0> extends true ? T1 : number, VariablePartOfArray<T>[number]>
|
|
26
|
+
: [],
|
|
25
27
|
> =
|
|
26
28
|
SplitIndex extends 0
|
|
27
29
|
? [[], T]
|
|
@@ -75,14 +75,9 @@ type CamelCasedPropertiesArrayDeep<Value extends UnknownArray> =
|
|
|
75
75
|
: // Leading spread array
|
|
76
76
|
Value extends readonly [...infer U, infer V]
|
|
77
77
|
? [...CamelCasedPropertiesDeep<U>, CamelCasedPropertiesDeep<V>]
|
|
78
|
-
:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
Value extends Array<infer U>
|
|
85
|
-
? Array<CamelCasedPropertiesDeep<U>>
|
|
86
|
-
: Value extends ReadonlyArray<infer U>
|
|
87
|
-
? ReadonlyArray<CamelCasedPropertiesDeep<U>>
|
|
88
|
-
: never;
|
|
78
|
+
: // Array
|
|
79
|
+
Value extends Array<infer U>
|
|
80
|
+
? Array<CamelCasedPropertiesDeep<U>>
|
|
81
|
+
: Value extends ReadonlyArray<infer U>
|
|
82
|
+
? ReadonlyArray<CamelCasedPropertiesDeep<U>>
|
|
83
|
+
: never;
|
|
@@ -1,54 +1,23 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
// Transforms a string that is fully uppercase into a fully lowercase version. Needed to add support for SCREAMING_SNAKE_CASE, see https://github.com/sindresorhus/type-fest/issues/385
|
|
4
|
-
type UpperCaseToLowerCase<T extends string> = T extends Uppercase<T> ? Lowercase<T> : T;
|
|
5
|
-
|
|
6
|
-
// This implementation does not support SCREAMING_SNAKE_CASE, it is used internally by `SplitIncludingDelimiters`.
|
|
7
|
-
type SplitIncludingDelimiters_<Source extends string, Delimiter extends string> =
|
|
8
|
-
Source extends '' ? [] :
|
|
9
|
-
Source extends `${infer FirstPart}${Delimiter}${infer SecondPart}` ?
|
|
10
|
-
(
|
|
11
|
-
Source extends `${FirstPart}${infer UsedDelimiter}${SecondPart}`
|
|
12
|
-
? UsedDelimiter extends Delimiter
|
|
13
|
-
? Source extends `${infer FirstPart}${UsedDelimiter}${infer SecondPart}`
|
|
14
|
-
? [...SplitIncludingDelimiters<FirstPart, Delimiter>, UsedDelimiter, ...SplitIncludingDelimiters<SecondPart, Delimiter>]
|
|
15
|
-
: never
|
|
16
|
-
: never
|
|
17
|
-
: never
|
|
18
|
-
) :
|
|
19
|
-
[Source];
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
Unlike a simpler split, this one includes the delimiter splitted on in the resulting array literal. This is to enable splitting on, for example, upper-case characters.
|
|
23
|
-
|
|
24
|
-
@category Template literal
|
|
25
|
-
*/
|
|
26
|
-
export type SplitIncludingDelimiters<Source extends string, Delimiter extends string> = SplitIncludingDelimiters_<UpperCaseToLowerCase<Source>, Delimiter>;
|
|
1
|
+
import type {IsStringLiteral} from './is-literal';
|
|
2
|
+
import type {Words, WordsOptions} from './words';
|
|
27
3
|
|
|
28
4
|
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@see StringArrayToDelimiterCase
|
|
5
|
+
Convert an array of words to delimiter case starting with a delimiter with input capitalization.
|
|
32
6
|
*/
|
|
33
|
-
type
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
Parts extends [`${infer FirstPart}`, ...infer RemainingParts]
|
|
48
|
-
? `${StringPartToDelimiterCase<FirstPart, Start, UsedWordSeparators, UsedUpperCaseCharacters, Delimiter>}${StringArrayToDelimiterCase<RemainingParts, false, UsedWordSeparators, UsedUpperCaseCharacters, Delimiter>}`
|
|
49
|
-
: Parts extends [string]
|
|
50
|
-
? string
|
|
51
|
-
: '';
|
|
7
|
+
type DelimiterCaseFromArray<
|
|
8
|
+
Words extends string[],
|
|
9
|
+
Delimiter extends string,
|
|
10
|
+
OutputString extends string = '',
|
|
11
|
+
> = Words extends [
|
|
12
|
+
infer FirstWord extends string,
|
|
13
|
+
...infer RemainingWords extends string[],
|
|
14
|
+
]
|
|
15
|
+
? DelimiterCaseFromArray<RemainingWords, Delimiter, `${OutputString}${Delimiter}${FirstWord}`>
|
|
16
|
+
: OutputString;
|
|
17
|
+
|
|
18
|
+
type RemoveFirstLetter<S extends string> = S extends `${infer _}${infer Rest}`
|
|
19
|
+
? Rest
|
|
20
|
+
: '';
|
|
52
21
|
|
|
53
22
|
/**
|
|
54
23
|
Convert a string literal to a custom string delimiter casing.
|
|
@@ -65,6 +34,7 @@ import type {DelimiterCase} from 'type-fest';
|
|
|
65
34
|
// Simple
|
|
66
35
|
|
|
67
36
|
const someVariable: DelimiterCase<'fooBar', '#'> = 'foo#bar';
|
|
37
|
+
const someVariableNoSplitOnNumbers: DelimiterCase<'p2pNetwork', '#', {splitOnNumbers: false}> = 'p2p#network';
|
|
68
38
|
|
|
69
39
|
// Advanced
|
|
70
40
|
|
|
@@ -87,13 +57,17 @@ const rawCliOptions: OddlyCasedProperties<SomeOptions> = {
|
|
|
87
57
|
|
|
88
58
|
@category Change case
|
|
89
59
|
@category Template literal
|
|
90
|
-
*/
|
|
91
|
-
export type DelimiterCase<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
60
|
+
*/
|
|
61
|
+
export type DelimiterCase<
|
|
62
|
+
Value,
|
|
63
|
+
Delimiter extends string,
|
|
64
|
+
Options extends WordsOptions = {splitOnNumbers: false},
|
|
65
|
+
> = Value extends string
|
|
66
|
+
? IsStringLiteral<Value> extends false
|
|
67
|
+
? Value
|
|
68
|
+
: Lowercase<
|
|
69
|
+
RemoveFirstLetter<
|
|
70
|
+
DelimiterCaseFromArray<Words<Value, Options>, Delimiter>
|
|
71
|
+
>
|
|
72
|
+
>
|
|
99
73
|
: Value;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {IsNever} from '../is-never';
|
|
2
|
+
import type {NegativeInfinity, PositiveInfinity} from '../numeric';
|
|
2
3
|
import type {UnknownArray} from '../unknown-array';
|
|
3
4
|
import type {StringToNumber} from './string';
|
|
4
5
|
|
|
@@ -89,3 +90,29 @@ type InternalUnionMax<N extends number, T extends UnknownArray = []> =
|
|
|
89
90
|
: T['length'] extends N
|
|
90
91
|
? InternalUnionMax<Exclude<N, T['length']>, T>
|
|
91
92
|
: InternalUnionMax<N, [...T, unknown]>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
Returns the number with reversed sign.
|
|
96
|
+
|
|
97
|
+
@example
|
|
98
|
+
```
|
|
99
|
+
ReverseSign<-1>;
|
|
100
|
+
//=> 1
|
|
101
|
+
|
|
102
|
+
ReverseSign<1>;
|
|
103
|
+
//=> -1
|
|
104
|
+
|
|
105
|
+
ReverseSign<NegativeInfinity>
|
|
106
|
+
//=> PositiveInfinity
|
|
107
|
+
|
|
108
|
+
ReverseSign<PositiveInfinity>
|
|
109
|
+
//=> NegativeInfinity
|
|
110
|
+
```
|
|
111
|
+
*/
|
|
112
|
+
export type ReverseSign<N extends number> =
|
|
113
|
+
// Handle edge cases
|
|
114
|
+
N extends 0 ? 0 : N extends PositiveInfinity ? NegativeInfinity : N extends NegativeInfinity ? PositiveInfinity :
|
|
115
|
+
// Handle negative numbers
|
|
116
|
+
`${N}` extends `-${infer P extends number}` ? P
|
|
117
|
+
// Handle positive numbers
|
|
118
|
+
: `-${N}` extends `${infer R extends number}` ? R : never;
|
package/source/kebab-case.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {DelimiterCase} from './delimiter-case';
|
|
2
|
+
import type {WordsOptions} from './words';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
Convert a string literal to kebab-case.
|
|
@@ -12,6 +13,7 @@ import type {KebabCase} from 'type-fest';
|
|
|
12
13
|
// Simple
|
|
13
14
|
|
|
14
15
|
const someVariable: KebabCase<'fooBar'> = 'foo-bar';
|
|
16
|
+
const someVariableNoSplitOnNumbers: KebabCase<'p2pNetwork', {splitOnNumbers: false}> = 'p2p-network';
|
|
15
17
|
|
|
16
18
|
// Advanced
|
|
17
19
|
|
|
@@ -35,4 +37,7 @@ const rawCliOptions: KebabCasedProperties<CliOptions> = {
|
|
|
35
37
|
@category Change case
|
|
36
38
|
@category Template literal
|
|
37
39
|
*/
|
|
38
|
-
export type KebabCase<
|
|
40
|
+
export type KebabCase<
|
|
41
|
+
Value,
|
|
42
|
+
Options extends WordsOptions = {splitOnNumbers: false},
|
|
43
|
+
> = DelimiterCase<Value, '-', Options>;
|
package/source/paths.d.ts
CHANGED
|
@@ -246,13 +246,7 @@ type InternalPaths<T, Options extends Required<PathsOptions>> =
|
|
|
246
246
|
bracketNotation: Options['bracketNotation'];
|
|
247
247
|
maxRecursionDepth: Subtract<MaxDepth, 1>;
|
|
248
248
|
leavesOnly: Options['leavesOnly'];
|
|
249
|
-
depth: Options['depth']
|
|
250
|
-
? Depth extends 0 // Don't subtract further if `Depth` has reached `0`
|
|
251
|
-
? never
|
|
252
|
-
: ToString<Depth> extends `-${number}` // Don't subtract if `Depth` is -ve
|
|
253
|
-
? never
|
|
254
|
-
: Subtract<Options['depth'], 1> // If `Subtract` supported -ve numbers, then `depth` could have simply been `Subtract<Options['depth'], 1>`
|
|
255
|
-
: never; // Should never happen
|
|
249
|
+
depth: Subtract<Options['depth'], 1>;
|
|
256
250
|
}> extends infer SubPath
|
|
257
251
|
? SubPath extends string | number
|
|
258
252
|
? (
|
package/source/replace.d.ts
CHANGED
|
@@ -60,8 +60,20 @@ export type Replace<
|
|
|
60
60
|
Search extends string,
|
|
61
61
|
Replacement extends string,
|
|
62
62
|
Options extends ReplaceOptions = {},
|
|
63
|
-
> = Input
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
> = _Replace<Input, Search, Replacement, Options>;
|
|
64
|
+
|
|
65
|
+
type _Replace<
|
|
66
|
+
Input extends string,
|
|
67
|
+
Search extends string,
|
|
68
|
+
Replacement extends string,
|
|
69
|
+
Options extends ReplaceOptions,
|
|
70
|
+
Accumulator extends string = '',
|
|
71
|
+
> = Search extends string // For distributing `Search`
|
|
72
|
+
? Replacement extends string // For distributing `Replacement`
|
|
73
|
+
? Input extends `${infer Head}${Search}${infer Tail}`
|
|
74
|
+
? Options['all'] extends true
|
|
75
|
+
? _Replace<Tail, Search, Replacement, Options, `${Accumulator}${Head}${Replacement}`>
|
|
76
|
+
: `${Head}${Replacement}${Tail}`
|
|
77
|
+
: `${Accumulator}${Input}`
|
|
78
|
+
: never
|
|
79
|
+
: never;
|
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
import type {SplitIncludingDelimiters} from './delimiter-case';
|
|
2
1
|
import type {SnakeCase} from './snake-case';
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
Returns a boolean for whether the string is screaming snake case.
|
|
7
|
-
*/
|
|
8
|
-
type IsScreamingSnakeCase<Value extends string> = Value extends Uppercase<Value>
|
|
9
|
-
? Includes<SplitIncludingDelimiters<Lowercase<Value>, '_'>, '_'> extends true
|
|
10
|
-
? true
|
|
11
|
-
: false
|
|
12
|
-
: false;
|
|
2
|
+
import type {WordsOptions} from './words';
|
|
13
3
|
|
|
14
4
|
/**
|
|
15
5
|
Convert a string literal to screaming-snake-case.
|
|
@@ -21,13 +11,14 @@ This can be useful when, for example, converting a camel-cased object property t
|
|
|
21
11
|
import type {ScreamingSnakeCase} from 'type-fest';
|
|
22
12
|
|
|
23
13
|
const someVariable: ScreamingSnakeCase<'fooBar'> = 'FOO_BAR';
|
|
14
|
+
const someVariableNoSplitOnNumbers: ScreamingSnakeCase<'p2pNetwork', {splitOnNumbers: false}> = 'P2P_NETWORK';
|
|
15
|
+
|
|
24
16
|
```
|
|
25
17
|
|
|
26
18
|
@category Change case
|
|
27
19
|
@category Template literal
|
|
28
|
-
*/
|
|
29
|
-
export type ScreamingSnakeCase<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
: Value;
|
|
20
|
+
*/
|
|
21
|
+
export type ScreamingSnakeCase<
|
|
22
|
+
Value,
|
|
23
|
+
Options extends WordsOptions = {splitOnNumbers: false},
|
|
24
|
+
> = Value extends string ? Uppercase<SnakeCase<Value, Options>> : Value;
|
package/source/snake-case.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {DelimiterCase} from './delimiter-case';
|
|
2
|
+
import type {WordsOptions} from './words';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
Convert a string literal to snake-case.
|
|
@@ -12,6 +13,7 @@ import type {SnakeCase} from 'type-fest';
|
|
|
12
13
|
// Simple
|
|
13
14
|
|
|
14
15
|
const someVariable: SnakeCase<'fooBar'> = 'foo_bar';
|
|
16
|
+
const someVariableNoSplitOnNumbers: SnakeCase<'p2pNetwork', {splitOnNumbers: false}> = 'p2p_network';
|
|
15
17
|
|
|
16
18
|
// Advanced
|
|
17
19
|
|
|
@@ -35,4 +37,7 @@ const dbResult: SnakeCasedProperties<ModelProps> = {
|
|
|
35
37
|
@category Change case
|
|
36
38
|
@category Template literal
|
|
37
39
|
*/
|
|
38
|
-
export type SnakeCase<
|
|
40
|
+
export type SnakeCase<
|
|
41
|
+
Value,
|
|
42
|
+
Options extends WordsOptions = {splitOnNumbers: false},
|
|
43
|
+
> = DelimiterCase<Value, '_', Options>;
|
package/source/split.d.ts
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
import type {And} from './and';
|
|
2
|
+
import type {Not} from './internal';
|
|
3
|
+
import type {IsStringLiteral} from './is-literal';
|
|
4
|
+
import type {Or} from './or';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
Split options.
|
|
8
|
+
|
|
9
|
+
@see {@link Split}
|
|
10
|
+
*/
|
|
11
|
+
type SplitOptions = {
|
|
12
|
+
/**
|
|
13
|
+
When enabled, instantiations with non-literal string types (e.g., `string`, `Uppercase<string>`, `on${string}`) simply return back `string[]` without performing any splitting, as the exact structure cannot be statically determined.
|
|
14
|
+
|
|
15
|
+
Note: In the future, this option might be enabled by default, so if you currently rely on this being disabled, you should consider explicitly enabling it.
|
|
16
|
+
|
|
17
|
+
@default false
|
|
18
|
+
|
|
19
|
+
@example
|
|
20
|
+
```ts
|
|
21
|
+
type Example1 = Split<`foo.${string}.bar`, '.', {strictLiteralChecks: false}>;
|
|
22
|
+
//=> ['foo', string, 'bar']
|
|
23
|
+
|
|
24
|
+
type Example2 = Split<`foo.${string}`, '.', {strictLiteralChecks: true}>;
|
|
25
|
+
//=> string[]
|
|
26
|
+
|
|
27
|
+
type Example3 = Split<'foobarbaz', `b${string}`, {strictLiteralChecks: false}>;
|
|
28
|
+
//=> ['foo', 'r', 'z']
|
|
29
|
+
|
|
30
|
+
type Example4 = Split<'foobarbaz', `b${string}`, {strictLiteralChecks: true}>;
|
|
31
|
+
//=> string[]
|
|
32
|
+
```
|
|
33
|
+
*/
|
|
34
|
+
strictLiteralChecks?: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type DefaultSplitOptions = {
|
|
38
|
+
strictLiteralChecks: false;
|
|
39
|
+
};
|
|
40
|
+
|
|
1
41
|
/**
|
|
2
42
|
Represents an array of strings split using a given character or character set.
|
|
3
43
|
|
|
@@ -16,20 +56,34 @@ let array: Item[];
|
|
|
16
56
|
array = split(items, ',');
|
|
17
57
|
```
|
|
18
58
|
|
|
59
|
+
@see {@link SplitOptions}
|
|
60
|
+
|
|
19
61
|
@category String
|
|
20
62
|
@category Template literal
|
|
21
63
|
*/
|
|
22
64
|
export type Split<
|
|
23
65
|
S extends string,
|
|
24
66
|
Delimiter extends string,
|
|
25
|
-
|
|
67
|
+
Options extends SplitOptions = {},
|
|
68
|
+
> = SplitHelper<S, Delimiter, {
|
|
69
|
+
strictLiteralChecks: Options['strictLiteralChecks'] extends boolean ? Options['strictLiteralChecks'] : DefaultSplitOptions['strictLiteralChecks'];
|
|
70
|
+
}>;
|
|
26
71
|
|
|
27
72
|
type SplitHelper<
|
|
28
73
|
S extends string,
|
|
29
74
|
Delimiter extends string,
|
|
75
|
+
Options extends Required<SplitOptions>,
|
|
30
76
|
Accumulator extends string[] = [],
|
|
31
|
-
> = S extends
|
|
32
|
-
?
|
|
33
|
-
|
|
34
|
-
?
|
|
35
|
-
|
|
77
|
+
> = S extends string // For distributing `S`
|
|
78
|
+
? Delimiter extends string // For distributing `Delimeter`
|
|
79
|
+
// If `strictLiteralChecks` is `false` OR `S` and `Delimiter` both are string literals, then perform the split
|
|
80
|
+
? Or<Not<Options['strictLiteralChecks']>, And<IsStringLiteral<S>, IsStringLiteral<Delimiter>>> extends true
|
|
81
|
+
? S extends `${infer Head}${Delimiter}${infer Tail}`
|
|
82
|
+
? SplitHelper<Tail, Delimiter, Options, [...Accumulator, Head]>
|
|
83
|
+
: Delimiter extends ''
|
|
84
|
+
? Accumulator
|
|
85
|
+
: [...Accumulator, S]
|
|
86
|
+
// Otherwise, return `string[]`
|
|
87
|
+
: string[]
|
|
88
|
+
: never // Should never happen
|
|
89
|
+
: never; // Should never happen
|
package/source/subtract.d.ts
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
import type {NumberAbsolute, BuildTuple} from './internal';
|
|
2
|
-
import type {IsEqual} from './is-equal';
|
|
1
|
+
import type {NumberAbsolute, BuildTuple, ReverseSign} from './internal';
|
|
3
2
|
import type {PositiveInfinity, NegativeInfinity, IsNegative} from './numeric';
|
|
4
3
|
import type {LessThan} from './less-than';
|
|
5
|
-
import type {Sum} from './sum';
|
|
6
|
-
import type {And} from './and';
|
|
7
|
-
import type {Or} from './or';
|
|
8
4
|
|
|
9
5
|
/**
|
|
10
6
|
Returns the difference between two numbers.
|
|
11
7
|
|
|
12
8
|
Note:
|
|
13
9
|
- A or B can only support `-999` ~ `999`.
|
|
14
|
-
- If the result is negative, you can only get `number`.
|
|
15
10
|
|
|
16
11
|
@example
|
|
17
12
|
```
|
|
@@ -24,7 +19,10 @@ Subtract<111, -222>;
|
|
|
24
19
|
//=> 333
|
|
25
20
|
|
|
26
21
|
Subtract<-111, 222>;
|
|
27
|
-
//=>
|
|
22
|
+
//=> -333
|
|
23
|
+
|
|
24
|
+
Subtract<18, 96>;
|
|
25
|
+
//=> -78
|
|
28
26
|
|
|
29
27
|
Subtract<PositiveInfinity, 9999>;
|
|
30
28
|
//=> PositiveInfinity
|
|
@@ -35,36 +33,51 @@ Subtract<PositiveInfinity, PositiveInfinity>;
|
|
|
35
33
|
|
|
36
34
|
@category Numeric
|
|
37
35
|
*/
|
|
38
|
-
// TODO: Support big integer
|
|
39
|
-
export type Subtract<A extends number, B extends number> =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
36
|
+
// TODO: Support big integer.
|
|
37
|
+
export type Subtract<A extends number, B extends number> =
|
|
38
|
+
// Handle cases when A or B is the actual "number" type
|
|
39
|
+
number extends A | B ? number
|
|
40
|
+
// Handle cases when A and B are both +/- infinity
|
|
41
|
+
: A extends B & (PositiveInfinity | NegativeInfinity) ? number
|
|
42
|
+
// Handle cases when A is - infinity or B is + infinity
|
|
43
|
+
: A extends NegativeInfinity ? NegativeInfinity : B extends PositiveInfinity ? NegativeInfinity
|
|
44
|
+
// Handle cases when A is + infinity or B is - infinity
|
|
45
|
+
: A extends PositiveInfinity ? PositiveInfinity : B extends NegativeInfinity ? PositiveInfinity
|
|
46
|
+
// Handle case when numbers are equal to each other
|
|
47
|
+
: A extends B ? 0
|
|
48
|
+
// Handle cases when A or B is 0
|
|
49
|
+
: A extends 0 ? ReverseSign<B> : B extends 0 ? A
|
|
50
|
+
// Handle remaining regular cases
|
|
51
|
+
: SubtractPostChecks<A, B>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
Subtracts two numbers A and B, such that they are not equal and neither of them are 0, +/- infinity or the `number` type
|
|
55
|
+
*/
|
|
56
|
+
type SubtractPostChecks<A extends number, B extends number, AreNegative = [IsNegative<A>, IsNegative<B>]> =
|
|
57
|
+
AreNegative extends [false, false]
|
|
58
|
+
? SubtractPositives<A, B>
|
|
59
|
+
: AreNegative extends [true, true]
|
|
60
|
+
// When both numbers are negative we subtract the absolute values and then reverse the sign
|
|
61
|
+
? ReverseSign<SubtractPositives<NumberAbsolute<A>, NumberAbsolute<B>>>
|
|
62
|
+
// When the signs are different we can add the absolute values and then reverse the sign if A < B
|
|
63
|
+
: [...BuildTuple<NumberAbsolute<A>>, ...BuildTuple<NumberAbsolute<B>>] extends infer R extends unknown[]
|
|
64
|
+
? LessThan<A, B> extends true ? ReverseSign<R['length']> : R['length']
|
|
65
|
+
: never;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
Subtracts two positive numbers.
|
|
69
|
+
*/
|
|
70
|
+
type SubtractPositives<A extends number, B extends number> =
|
|
71
|
+
LessThan<A, B> extends true
|
|
72
|
+
// When A < B we can reverse the result of B - A
|
|
73
|
+
? ReverseSign<SubtractIfAGreaterThanB<B, A>>
|
|
74
|
+
: SubtractIfAGreaterThanB<A, B>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
Subtracts two positive numbers A and B such that A > B.
|
|
78
|
+
*/
|
|
79
|
+
type SubtractIfAGreaterThanB<A extends number, B extends number> =
|
|
80
|
+
// This is where we always want to end up and do the actual subtraction
|
|
81
|
+
BuildTuple<A> extends [...BuildTuple<B>, ...infer R]
|
|
82
|
+
? R['length']
|
|
70
83
|
: never;
|
package/source/sum.d.ts
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
import type {NumberAbsolute, BuildTuple, TupleMax,
|
|
2
|
-
import type {IsEqual} from './is-equal';
|
|
1
|
+
import type {NumberAbsolute, BuildTuple, TupleMax, ReverseSign} from './internal';
|
|
3
2
|
import type {PositiveInfinity, NegativeInfinity, IsNegative} from './numeric';
|
|
4
3
|
import type {Subtract} from './subtract';
|
|
5
|
-
import type {And} from './and';
|
|
6
|
-
import type {Or} from './or';
|
|
7
4
|
|
|
8
5
|
/**
|
|
9
6
|
Returns the sum of two numbers.
|
|
10
7
|
|
|
11
8
|
Note:
|
|
12
9
|
- A or B can only support `-999` ~ `999`.
|
|
13
|
-
- A and B can only be small integers, less than 1000.
|
|
14
|
-
- If the result is negative, you can only get `number`.
|
|
15
10
|
|
|
16
11
|
@example
|
|
17
12
|
```
|
|
@@ -24,7 +19,7 @@ Sum<-111, 222>;
|
|
|
24
19
|
//=> 111
|
|
25
20
|
|
|
26
21
|
Sum<111, -222>;
|
|
27
|
-
//=>
|
|
22
|
+
//=> -111
|
|
28
23
|
|
|
29
24
|
Sum<PositiveInfinity, -9999>;
|
|
30
25
|
//=> PositiveInfinity
|
|
@@ -35,36 +30,49 @@ Sum<PositiveInfinity, NegativeInfinity>;
|
|
|
35
30
|
|
|
36
31
|
@category Numeric
|
|
37
32
|
*/
|
|
38
|
-
// TODO: Support big integer
|
|
39
|
-
export type Sum<A extends number, B extends number> =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
33
|
+
// TODO: Support big integer.
|
|
34
|
+
export type Sum<A extends number, B extends number> =
|
|
35
|
+
// Handle cases when A or B is the actual "number" type
|
|
36
|
+
number extends A | B ? number
|
|
37
|
+
// Handle cases when A and B are both +/- infinity
|
|
38
|
+
: A extends B & (PositiveInfinity | NegativeInfinity) ? A // A or B could be used here as they are equal
|
|
39
|
+
// Handle cases when A and B are opposite infinities
|
|
40
|
+
: A | B extends PositiveInfinity | NegativeInfinity ? number
|
|
41
|
+
// Handle cases when A is +/- infinity
|
|
42
|
+
: A extends PositiveInfinity | NegativeInfinity ? A
|
|
43
|
+
// Handle cases when B is +/- infinity
|
|
44
|
+
: B extends PositiveInfinity | NegativeInfinity ? B
|
|
45
|
+
// Handle cases when A or B is 0 or it's the same number with different signs
|
|
46
|
+
: A extends 0 ? B : B extends 0 ? A : A extends ReverseSign<B> ? 0
|
|
47
|
+
// Handle remaining regular cases
|
|
48
|
+
: SumPostChecks<A, B>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
Adds two numbers A and B, such that they are not equal with different signs and neither of them are 0, +/- infinity or the `number` type
|
|
52
|
+
*/
|
|
53
|
+
type SumPostChecks<A extends number, B extends number, AreNegative = [IsNegative<A>, IsNegative<B>]> =
|
|
54
|
+
AreNegative extends [false, false]
|
|
55
|
+
// When both numbers are positive we can add them together
|
|
56
|
+
? SumPositives<A, B>
|
|
57
|
+
: AreNegative extends [true, true]
|
|
58
|
+
// When both numbers are negative we add the absolute values and then reverse the sign
|
|
59
|
+
? ReverseSign<SumPositives<NumberAbsolute<A>, NumberAbsolute<B>>>
|
|
60
|
+
// When the signs are different we can subtract the absolute values, remove the sign
|
|
61
|
+
// and then reverse the sign if the larger absolute value is negative
|
|
62
|
+
: NumberAbsolute<Subtract<NumberAbsolute<A>, NumberAbsolute<B>>> extends infer Result extends number
|
|
63
|
+
? TupleMax<[NumberAbsolute<A>, NumberAbsolute<B>]> extends infer Max_ extends number
|
|
64
|
+
? Max_ extends A | B
|
|
65
|
+
// The larger absolute value is positive, so the result is positive
|
|
66
|
+
? Result
|
|
67
|
+
// The larger absolute value is negative, so the result is negative
|
|
68
|
+
: ReverseSign<Result>
|
|
69
|
+
: never
|
|
70
|
+
: never;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
Adds two positive numbers.
|
|
74
|
+
*/
|
|
75
|
+
type SumPositives<A extends number, B extends number> =
|
|
76
|
+
[...BuildTuple<A>, ...BuildTuple<B>]['length'] extends infer Result extends number
|
|
77
|
+
? Result
|
|
70
78
|
: never;
|
|
@@ -18,6 +18,7 @@ declare namespace TsConfigJson {
|
|
|
18
18
|
| 'ES2022'
|
|
19
19
|
| 'ESNext'
|
|
20
20
|
| 'Node16'
|
|
21
|
+
| 'Node18'
|
|
21
22
|
| 'NodeNext'
|
|
22
23
|
| 'Preserve'
|
|
23
24
|
| 'None'
|
|
@@ -32,6 +33,7 @@ declare namespace TsConfigJson {
|
|
|
32
33
|
| 'es2022'
|
|
33
34
|
| 'esnext'
|
|
34
35
|
| 'node16'
|
|
36
|
+
| 'node18'
|
|
35
37
|
| 'nodenext'
|
|
36
38
|
| 'preserve'
|
|
37
39
|
| 'none';
|
|
@@ -1109,6 +1111,20 @@ declare namespace TsConfigJson {
|
|
|
1109
1111
|
Suppress deprecation warnings
|
|
1110
1112
|
*/
|
|
1111
1113
|
ignoreDeprecations?: CompilerOptions.IgnoreDeprecations;
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
Do not allow runtime constructs that are not part of ECMAScript.
|
|
1117
|
+
|
|
1118
|
+
@default false
|
|
1119
|
+
*/
|
|
1120
|
+
erasableSyntaxOnly?: boolean;
|
|
1121
|
+
|
|
1122
|
+
/**
|
|
1123
|
+
Enable lib replacement.
|
|
1124
|
+
|
|
1125
|
+
@default true
|
|
1126
|
+
*/
|
|
1127
|
+
libReplacement?: boolean;
|
|
1112
1128
|
};
|
|
1113
1129
|
|
|
1114
1130
|
namespace WatchOptions {
|
|
@@ -1160,12 +1176,12 @@ declare namespace TsConfigJson {
|
|
|
1160
1176
|
synchronousWatchDirectory?: boolean;
|
|
1161
1177
|
|
|
1162
1178
|
/**
|
|
1163
|
-
Specifies a list of directories to exclude from watch
|
|
1179
|
+
Specifies a list of directories to exclude from watch.
|
|
1164
1180
|
*/
|
|
1165
1181
|
excludeDirectories?: string[];
|
|
1166
1182
|
|
|
1167
1183
|
/**
|
|
1168
|
-
Specifies a list of files to exclude from watch
|
|
1184
|
+
Specifies a list of files to exclude from watch.
|
|
1169
1185
|
*/
|
|
1170
1186
|
excludeFiles?: string[];
|
|
1171
1187
|
};
|
package/source/words.d.ts
CHANGED
|
@@ -1,11 +1,46 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
IsLowerCase,
|
|
3
|
+
IsNumeric,
|
|
4
|
+
IsUpperCase,
|
|
5
|
+
WordSeparators,
|
|
6
|
+
} from './internal';
|
|
2
7
|
|
|
3
8
|
type SkipEmptyWord<Word extends string> = Word extends '' ? [] : [Word];
|
|
4
9
|
|
|
5
|
-
type RemoveLastCharacter<
|
|
10
|
+
type RemoveLastCharacter<
|
|
11
|
+
Sentence extends string,
|
|
12
|
+
Character extends string,
|
|
13
|
+
> = Sentence extends `${infer LeftSide}${Character}`
|
|
6
14
|
? SkipEmptyWord<LeftSide>
|
|
7
15
|
: never;
|
|
8
16
|
|
|
17
|
+
/**
|
|
18
|
+
Words options.
|
|
19
|
+
|
|
20
|
+
@see {@link Words}
|
|
21
|
+
*/
|
|
22
|
+
export type WordsOptions = {
|
|
23
|
+
/**
|
|
24
|
+
Split on numeric sequence.
|
|
25
|
+
|
|
26
|
+
@default true
|
|
27
|
+
|
|
28
|
+
@example
|
|
29
|
+
```
|
|
30
|
+
type Example1 = Words<'p2pNetwork', {splitOnNumbers: true}>;
|
|
31
|
+
//=> ["p", "2", "p", "Network"]
|
|
32
|
+
|
|
33
|
+
type Example2 = Words<'p2pNetwork', {splitOnNumbers: false}>;
|
|
34
|
+
//=> ["p2p", "Network"]
|
|
35
|
+
```
|
|
36
|
+
*/
|
|
37
|
+
splitOnNumbers?: boolean;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
type DefaultOptions = {
|
|
41
|
+
splitOnNumbers: true;
|
|
42
|
+
};
|
|
43
|
+
|
|
9
44
|
/**
|
|
10
45
|
Split a string (almost) like Lodash's `_.words()` function.
|
|
11
46
|
|
|
@@ -31,37 +66,53 @@ type Words3 = Words<'--hello the_world'>;
|
|
|
31
66
|
|
|
32
67
|
type Words4 = Words<'lifeIs42'>;
|
|
33
68
|
//=> ['life', 'Is', '42']
|
|
69
|
+
|
|
70
|
+
type Words5 = Words<'p2pNetwork', {splitOnNumbers: false}>;
|
|
71
|
+
//=> ['p2p', 'Network']
|
|
34
72
|
```
|
|
35
73
|
|
|
36
74
|
@category Change case
|
|
37
75
|
@category Template literal
|
|
38
76
|
*/
|
|
39
|
-
export type Words<
|
|
77
|
+
export type Words<Sentence extends string, Options extends WordsOptions = {}> = WordsImplementation<Sentence, {
|
|
78
|
+
splitOnNumbers: Options['splitOnNumbers'] extends boolean ? Options['splitOnNumbers'] : DefaultOptions['splitOnNumbers'];
|
|
79
|
+
}>;
|
|
80
|
+
|
|
81
|
+
type WordsImplementation<
|
|
40
82
|
Sentence extends string,
|
|
83
|
+
Options extends Required<WordsOptions>,
|
|
41
84
|
LastCharacter extends string = '',
|
|
42
85
|
CurrentWord extends string = '',
|
|
43
86
|
> = Sentence extends `${infer FirstCharacter}${infer RemainingCharacters}`
|
|
44
87
|
? FirstCharacter extends WordSeparators
|
|
45
88
|
// Skip word separator
|
|
46
|
-
? [...SkipEmptyWord<CurrentWord>, ...
|
|
89
|
+
? [...SkipEmptyWord<CurrentWord>, ...WordsImplementation<RemainingCharacters, Options>]
|
|
47
90
|
: LastCharacter extends ''
|
|
48
91
|
// Fist char of word
|
|
49
|
-
?
|
|
50
|
-
// Case change: non-numeric to numeric
|
|
92
|
+
? WordsImplementation<RemainingCharacters, Options, FirstCharacter, FirstCharacter>
|
|
93
|
+
// Case change: non-numeric to numeric
|
|
51
94
|
: [false, true] extends [IsNumeric<LastCharacter>, IsNumeric<FirstCharacter>]
|
|
52
|
-
? [
|
|
53
|
-
|
|
95
|
+
? Options['splitOnNumbers'] extends true
|
|
96
|
+
// Split on number: push word
|
|
97
|
+
? [...SkipEmptyWord<CurrentWord>, ...WordsImplementation<RemainingCharacters, Options, FirstCharacter, FirstCharacter>]
|
|
98
|
+
// No split on number: concat word
|
|
99
|
+
: WordsImplementation<RemainingCharacters, Options, FirstCharacter, `${CurrentWord}${FirstCharacter}`>
|
|
100
|
+
// Case change: numeric to non-numeric
|
|
54
101
|
: [true, false] extends [IsNumeric<LastCharacter>, IsNumeric<FirstCharacter>]
|
|
55
|
-
? [
|
|
102
|
+
? Options['splitOnNumbers'] extends true
|
|
103
|
+
// Split on number: push word
|
|
104
|
+
? [...SkipEmptyWord<CurrentWord>, ...WordsImplementation<RemainingCharacters, Options, FirstCharacter, FirstCharacter>]
|
|
105
|
+
// No split on number: concat word
|
|
106
|
+
: WordsImplementation<RemainingCharacters, Options, FirstCharacter, `${CurrentWord}${FirstCharacter}`>
|
|
56
107
|
// No case change: concat word
|
|
57
108
|
: [true, true] extends [IsNumeric<LastCharacter>, IsNumeric<FirstCharacter>]
|
|
58
|
-
?
|
|
109
|
+
? WordsImplementation<RemainingCharacters, Options, FirstCharacter, `${CurrentWord}${FirstCharacter}`>
|
|
59
110
|
// Case change: lower to upper, push word
|
|
60
111
|
: [true, true] extends [IsLowerCase<LastCharacter>, IsUpperCase<FirstCharacter>]
|
|
61
|
-
? [...SkipEmptyWord<CurrentWord>, ...
|
|
112
|
+
? [...SkipEmptyWord<CurrentWord>, ...WordsImplementation<RemainingCharacters, Options, FirstCharacter, FirstCharacter>]
|
|
62
113
|
// Case change: upper to lower, brings back the last character, push word
|
|
63
114
|
: [true, true] extends [IsUpperCase<LastCharacter>, IsLowerCase<FirstCharacter>]
|
|
64
|
-
? [...RemoveLastCharacter<CurrentWord, LastCharacter>, ...
|
|
115
|
+
? [...RemoveLastCharacter<CurrentWord, LastCharacter>, ...WordsImplementation<RemainingCharacters, Options, FirstCharacter, `${LastCharacter}${FirstCharacter}`>]
|
|
65
116
|
// No case change: concat word
|
|
66
|
-
:
|
|
117
|
+
: WordsImplementation<RemainingCharacters, Options, FirstCharacter, `${CurrentWord}${FirstCharacter}`>
|
|
67
118
|
: [...SkipEmptyWord<CurrentWord>];
|