type-fest 4.23.0 → 4.25.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/index.d.ts CHANGED
@@ -36,6 +36,7 @@ export type {UndefinedOnPartialDeep} from './source/undefined-on-partial-deep';
36
36
  export type {ReadonlyDeep} from './source/readonly-deep';
37
37
  export type {LiteralUnion} from './source/literal-union';
38
38
  export type {Promisable} from './source/promisable';
39
+ export type {Arrayable} from './source/arrayable';
39
40
  export type {Opaque, UnwrapOpaque, Tagged, GetTagMetadata, UnwrapTagged} from './source/opaque';
40
41
  export type {InvariantOf} from './source/invariant-of';
41
42
  export type {SetOptional} from './source/set-optional';
@@ -154,6 +155,7 @@ export type {Join} from './source/join';
154
155
  export type {Split} from './source/split';
155
156
  export type {Trim} from './source/trim';
156
157
  export type {Replace} from './source/replace';
158
+ export type {StringRepeat} from './source/string-repeat';
157
159
  export type {Includes} from './source/includes';
158
160
  export type {Get} from './source/get';
159
161
  export type {LastArrayElement} from './source/last-array-element';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-fest",
3
- "version": "4.23.0",
3
+ "version": "4.25.0",
4
4
  "description": "A collection of essential TypeScript types",
5
5
  "license": "(MIT OR CC0-1.0)",
6
6
  "repository": "sindresorhus/type-fest",
package/readme.md CHANGED
@@ -269,9 +269,11 @@ type ShouldBeNever = IfAny<'not any', 'not never', 'never'>;
269
269
  - [`Split`](source/split.d.ts) - Represents an array of strings split using a given character or character set.
270
270
  - [`Replace`](source/replace.d.ts) - Represents a string with some or all matches replaced by a replacement.
271
271
  - [`StringSlice`](source/string-slice.d.ts) - Returns a string slice of a given range, just like `String#slice()`.
272
+ - [`StringRepeat`](source/string-repeat.d.ts) - Returns a new string which contains the specified number of copies of a given string, just like `String#repeat()`.
272
273
 
273
274
  ### Array
274
275
 
276
+ - [`Arrayable`](source/arrayable.d.ts) - Create a type that represents either the value or an array of the value.
275
277
  - [`Includes`](source/includes.d.ts) - Returns a boolean for whether the given array includes the given item.
276
278
  - [`Join`](source/join.d.ts) - Join an array of strings and/or numbers using the given string as a delimiter.
277
279
  - [`ArraySlice`](source/array-slice.d.ts) - Returns an array slice of a given range, just like `Array#slice()`.
@@ -0,0 +1,26 @@
1
+ /**
2
+ Create a type that represents either the value or an array of the value.
3
+
4
+ @see Promisable
5
+
6
+ @example
7
+ ```
8
+ import type {Arrayable} from 'type-fest';
9
+
10
+ function bundle(input: string, output: Arrayable<string>) {
11
+ const outputList = Array.isArray(output) ? output : [output];
12
+
13
+ // …
14
+
15
+ for (const output of outputList) {
16
+ console.log(`write to: ${output}`);
17
+ }
18
+ }
19
+
20
+ bundle('src/index.js', 'dist/index.js');
21
+ bundle('src/index.js', ['dist/index.cjs', 'dist/index.mjs']);
22
+ ```
23
+
24
+ @category Array
25
+ */
26
+ export type Arrayable<T> = T | readonly T[];
@@ -19,6 +19,33 @@ NumberAbsolute<NegativeInfinity>
19
19
  */
20
20
  export type NumberAbsolute<N extends number> = `${N}` extends `-${infer StringPositiveN}` ? StringToNumber<StringPositiveN> : N;
21
21
 
22
+ /**
23
+ Check whether the given type is a number or a number string.
24
+
25
+ Supports floating-point as a string.
26
+
27
+ @example
28
+ ```
29
+ type A = IsNumberLike<'1'>;
30
+ //=> true
31
+
32
+ type B = IsNumberLike<'-1.1'>;
33
+ //=> true
34
+
35
+ type C = IsNumberLike<1>;
36
+ //=> true
37
+
38
+ type D = IsNumberLike<'a'>;
39
+ //=> false
40
+ */
41
+ export type IsNumberLike<N> =
42
+ N extends number ? true
43
+ : N extends `${number}`
44
+ ? true
45
+ : N extends `${number}.${number}`
46
+ ? true
47
+ : false;
48
+
22
49
  /**
23
50
  Returns the minimum number in the given union of numbers.
24
51
 
@@ -322,7 +322,7 @@ export type MergeDeepOptions = {
322
322
 
323
323
  Note: Top-level arrays and tuples are always spread.
324
324
 
325
- @default 'spread'
325
+ @default 'replace'
326
326
  */
327
327
  arrayMergeMode?: ArrayMergeMode;
328
328
 
@@ -37,6 +37,25 @@ type UsefulInfo = OmitDeep<Info, 'userInfo.uselessInfo'>;
37
37
  // userInfo: {
38
38
  // name: string;
39
39
  // };
40
+ // };
41
+
42
+ // Supports removing multiple paths
43
+ type Info1 = {
44
+ userInfo: {
45
+ name: string;
46
+ uselessField: string;
47
+ uselessInfo: {
48
+ foo: string;
49
+ };
50
+ };
51
+ };
52
+
53
+ type UsefulInfo1 = OmitDeep<Info1, 'userInfo.uselessInfo' | 'userInfo.uselessField'>;
54
+ // type UsefulInfo1 = {
55
+ // userInfo: {
56
+ // name: string;
57
+ // };
58
+ // };
40
59
 
41
60
  // Supports array
42
61
  type A = OmitDeep<[1, 'foo', 2], 1>;
package/source/paths.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- import type {StaticPartOfArray, VariablePartOfArray, NonRecursiveType, ToString} from './internal';
1
+ import type {StaticPartOfArray, VariablePartOfArray, NonRecursiveType, ToString, IsNumberLike} from './internal';
2
2
  import type {EmptyObject} from './empty-object';
3
3
  import type {IsAny} from './is-any';
4
- import type {IsNever} from './is-never';
5
4
  import type {UnknownArray} from './unknown-array';
6
5
  import type {Subtract} from './subtract';
7
6
  import type {GreaterThan} from './greater-than';
@@ -18,6 +17,44 @@ export type PathsOptions = {
18
17
  @default 10
19
18
  */
20
19
  maxRecursionDepth?: number;
20
+
21
+ /**
22
+ Use bracket notation for array indices and numeric object keys.
23
+
24
+ @default false
25
+
26
+ @example
27
+ ```
28
+ type ArrayExample = {
29
+ array: ['foo'];
30
+ };
31
+
32
+ type A = Paths<ArrayExample, {bracketNotation: false}>;
33
+ //=> 'array' | 'array.0'
34
+
35
+ type B = Paths<ArrayExample, {bracketNotation: true}>;
36
+ //=> 'array' | 'array[0]'
37
+ ```
38
+
39
+ @example
40
+ ```
41
+ type NumberKeyExample = {
42
+ 1: ['foo'];
43
+ };
44
+
45
+ type A = Paths<NumberKeyExample, {bracketNotation: false}>;
46
+ //=> 1 | '1' | '1.0'
47
+
48
+ type B = Paths<NumberKeyExample, {bracketNotation: true}>;
49
+ //=> '[1]' | '[1][0]'
50
+ ```
51
+ */
52
+ bracketNotation?: boolean;
53
+ };
54
+
55
+ type DefaultPathsOptions = {
56
+ maxRecursionDepth: 10;
57
+ bracketNotation: false;
21
58
  };
22
59
 
23
60
  /**
@@ -61,7 +98,14 @@ open('listB.1'); // TypeError. Because listB only has one element.
61
98
  @category Object
62
99
  @category Array
63
100
  */
64
- export type Paths<T, Options extends PathsOptions = {}> =
101
+ export type Paths<T, Options extends PathsOptions = {}> = _Paths<T, {
102
+ // Set default maxRecursionDepth to 10
103
+ maxRecursionDepth: Options['maxRecursionDepth'] extends number ? Options['maxRecursionDepth'] : DefaultPathsOptions['maxRecursionDepth'];
104
+ // Set default bracketNotation to false
105
+ bracketNotation: Options['bracketNotation'] extends boolean ? Options['bracketNotation'] : DefaultPathsOptions['bracketNotation'];
106
+ }>;
107
+
108
+ type _Paths<T, Options extends Required<PathsOptions>> =
65
109
  T extends NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
66
110
  ? never
67
111
  : IsAny<T> extends true
@@ -76,25 +120,50 @@ export type Paths<T, Options extends PathsOptions = {}> =
76
120
  ? InternalPaths<T, Options>
77
121
  : never;
78
122
 
79
- type InternalPaths<T, Options extends PathsOptions = {}> =
80
- (Options['maxRecursionDepth'] extends number ? Options['maxRecursionDepth'] : 10) extends infer MaxDepth extends number
123
+ type InternalPaths<T, Options extends Required<PathsOptions>> =
124
+ Options['maxRecursionDepth'] extends infer MaxDepth extends number
81
125
  ? Required<T> extends infer T
82
126
  ? T extends EmptyObject | readonly []
83
127
  ? never
84
128
  : {
85
129
  [Key in keyof T]:
86
130
  Key extends string | number // Limit `Key` to string or number.
87
- // If `Key` is a number, return `Key | `${Key}``, because both `array[0]` and `array['0']` work.
88
- ?
89
- | Key
90
- | ToString<Key>
91
- | (
92
- GreaterThan<MaxDepth, 0> extends true // Limit the depth to prevent infinite recursion
93
- ? IsNever<Paths<T[Key], {maxRecursionDepth: Subtract<MaxDepth, 1>}>> extends false
94
- ? `${Key}.${Paths<T[Key], {maxRecursionDepth: Subtract<MaxDepth, 1>}>}`
95
- : never
131
+ ? (
132
+ Options['bracketNotation'] extends true
133
+ ? IsNumberLike<Key> extends true
134
+ ? `[${Key}]`
135
+ : (Key | ToString<Key>)
96
136
  : never
97
- )
137
+ |
138
+ Options['bracketNotation'] extends false
139
+ // If `Key` is a number, return `Key | `${Key}``, because both `array[0]` and `array['0']` work.
140
+ ? (Key | ToString<Key>)
141
+ : never
142
+ ) extends infer TranformedKey extends string | number ?
143
+ // 1. If style is 'a[0].b' and 'Key' is a numberlike value like 3 or '3', transform 'Key' to `[${Key}]`, else to `${Key}` | Key
144
+ // 2. If style is 'a.0.b', transform 'Key' to `${Key}` | Key
145
+ | TranformedKey
146
+ | (
147
+ // Recursively generate paths for the current key
148
+ GreaterThan<MaxDepth, 0> extends true // Limit the depth to prevent infinite recursion
149
+ ? _Paths<T[Key], {bracketNotation: Options['bracketNotation']; maxRecursionDepth: Subtract<MaxDepth, 1>}> extends infer SubPath
150
+ ? SubPath extends string | number
151
+ ? (
152
+ Options['bracketNotation'] extends true
153
+ ? SubPath extends `[${any}]` | `[${any}]${string}`
154
+ ? `${TranformedKey}${SubPath}` // If next node is number key like `[3]`, no need to add `.` before it.
155
+ : `${TranformedKey}.${SubPath}`
156
+ : never
157
+ ) | (
158
+ Options['bracketNotation'] extends false
159
+ ? `${TranformedKey}.${SubPath}`
160
+ : never
161
+ )
162
+ : never
163
+ : never
164
+ : never
165
+ )
166
+ : never
98
167
  : never
99
168
  }[keyof T & (T extends UnknownArray ? number : unknown)]
100
169
  : never
@@ -0,0 +1,43 @@
1
+ import type {IsNegative} from './numeric';
2
+ import type {Subtract} from './subtract';
3
+
4
+ /**
5
+ Returns a new string which contains the specified number of copies of a given string, just like `String#repeat()`.
6
+
7
+ @example
8
+ ```
9
+ import {StringRepeat} from 'type-fest';
10
+
11
+ declare function stringRepeat<
12
+ Input extends string,
13
+ Count extends number
14
+ >(input: Input, count: Count): StringRepeat<Input, Count>;
15
+
16
+ // The return type is the exact string literal, not just `string`.
17
+
18
+ stringRepeat('foo', 2);
19
+ //=> 'foofoo'
20
+
21
+ stringRepeat('=', 3);
22
+ //=> '==='
23
+ ```
24
+
25
+ @category String
26
+ @category Template literal
27
+ */
28
+ export type StringRepeat<
29
+ Input extends string,
30
+ Count extends number,
31
+ > = number extends Count
32
+ ? Input extends ''
33
+ ? ''
34
+ : string
35
+ : IsNegative<Count> extends true
36
+ ? never
37
+ : Count extends 0
38
+ ? ''
39
+ : string extends Input
40
+ ? string
41
+ : StringRepeat<Input, Subtract<Count, 1>> extends infer R extends string
42
+ ? `${Input}${R}`
43
+ : never;