type-fest 4.10.2 → 4.11.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
@@ -26,12 +26,13 @@ export type {PickIndexSignature} from './source/pick-index-signature';
26
26
  export type {PartialDeep, PartialDeepOptions} from './source/partial-deep';
27
27
  export type {RequiredDeep} from './source/required-deep';
28
28
  export type {PickDeep} from './source/pick-deep';
29
+ export type {OmitDeep} from './source/omit-deep';
29
30
  export type {PartialOnUndefinedDeep, PartialOnUndefinedDeepOptions} from './source/partial-on-undefined-deep';
30
31
  export type {UndefinedOnPartialDeep} from './source/undefined-on-partial-deep';
31
32
  export type {ReadonlyDeep} from './source/readonly-deep';
32
33
  export type {LiteralUnion} from './source/literal-union';
33
34
  export type {Promisable} from './source/promisable';
34
- export type {Opaque, UnwrapOpaque, Tagged, UnwrapTagged} from './source/opaque';
35
+ export type {Opaque, UnwrapOpaque, Tagged, GetTagMetadata, UnwrapTagged} from './source/opaque';
35
36
  export type {InvariantOf} from './source/invariant-of';
36
37
  export type {SetOptional} from './source/set-optional';
37
38
  export type {SetReadonly} from './source/set-readonly';
@@ -103,6 +104,7 @@ export type {IsUnknown} from './source/is-unknown';
103
104
  export type {IfUnknown} from './source/if-unknown';
104
105
  export type {ArrayIndices} from './source/array-indices';
105
106
  export type {ArrayValues} from './source/array-values';
107
+ export type {ArraySplice} from './source/array-splice';
106
108
  export type {SetFieldType} from './source/set-field-type';
107
109
  export type {Paths} from './source/paths';
108
110
  export type {SharedUnionFieldsDeep} from './source/shared-union-fields-deep';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-fest",
3
- "version": "4.10.2",
3
+ "version": "4.11.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
@@ -127,6 +127,7 @@ Click the type names for complete docs.
127
127
  - [`RequireOneOrNone`](source/require-one-or-none.d.ts) - Create a type that requires exactly a single key of the given keys and disallows more, or none of the given keys.
128
128
  - [`RequiredDeep`](source/required-deep.d.ts) - Create a deeply required version of another type. Use [`Required<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype) if you only need one level deep.
129
129
  - [`PickDeep`](source/pick-deep.d.ts) - Pick properties from a deeply-nested object. Use [`Pick<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys) if you only need one level deep.
130
+ - [`OmitDeep`](source/omit-deep.d.ts) - Omit properties from a deeply-nested object. Use [`Omit<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys) if you only need one level deep.
130
131
  - [`OmitIndexSignature`](source/omit-index-signature.d.ts) - Omit any index signatures from the given object type, leaving only explicitly defined properties.
131
132
  - [`PickIndexSignature`](source/pick-index-signature.d.ts) - Pick only index signatures from the given object type, leaving out all explicitly defined properties.
132
133
  - [`PartialDeep`](source/partial-deep.d.ts) - Create a deeply optional version of another type. Use [`Partial<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype) if you only need one level deep.
@@ -177,6 +178,7 @@ Click the type names for complete docs.
177
178
  - [`IntRange`](source/int-range.d.ts) - Generate a union of numbers.
178
179
  - [`ArrayIndices`](source/array-indices.d.ts) - Provides valid indices for a constant array or tuple.
179
180
  - [`ArrayValues`](source/array-values.d.ts) - Provides all values for a constant array or tuple.
181
+ - [`ArraySplice`](source/array-splice.d.ts) - Creates a new array type by adding or removing elements at a specified index range in the original array.
180
182
  - [`SetFieldType`](source/set-field-type.d.ts) - Create a type that changes the type of the given keys.
181
183
  - [`Paths`](source/paths.d.ts) - Generate a union of all possible paths to properties in the given object.
182
184
  - [`SharedUnionFieldsDeep`](source/shared-union-fields-deep.d.ts) - Create a type with shared fields from a union of object types, deeply traversing nested structures.
@@ -0,0 +1,95 @@
1
+ import type {BuildTuple, Subtract, StaticPartOfArray, VariablePartOfArray, GTE} from './internal';
2
+ import type {UnknownArray} from './unknown-array';
3
+
4
+ /**
5
+ The implementation of `SplitArrayByIndex` for fixed length arrays.
6
+ */
7
+ type SplitFixedArrayByIndex<T extends UnknownArray, SplitIndex extends number> =
8
+ SplitIndex extends 0
9
+ ? [[], T]
10
+ : T extends readonly [...BuildTuple<SplitIndex>, ...infer V]
11
+ ? T extends readonly [...infer U, ...V]
12
+ ? [U, V]
13
+ : [never, never]
14
+ : [never, never];
15
+
16
+ /**
17
+ The implementation of `SplitArrayByIndex` for variable length arrays.
18
+ */
19
+ type SplitVariableArrayByIndex<T extends UnknownArray,
20
+ SplitIndex extends number,
21
+ T1 = Subtract<SplitIndex, StaticPartOfArray<T>['length']>,
22
+ T2 = T1 extends number ? BuildTuple<T1, VariablePartOfArray<T>[number]> : [],
23
+ > =
24
+ SplitIndex extends 0
25
+ ? [[], T]
26
+ : GTE<StaticPartOfArray<T>['length'], SplitIndex> extends true
27
+ ? [
28
+ SplitFixedArrayByIndex<StaticPartOfArray<T>, SplitIndex>[0],
29
+ [
30
+ ...SplitFixedArrayByIndex<StaticPartOfArray<T>, SplitIndex>[1],
31
+ ...VariablePartOfArray<T>,
32
+ ],
33
+ ]
34
+ : [
35
+ [
36
+ ...StaticPartOfArray<T>,
37
+ ...(T2 extends UnknownArray ? T2 : []),
38
+ ],
39
+ VariablePartOfArray<T>,
40
+ ];
41
+
42
+ /**
43
+ Split the given array `T` by the given `SplitIndex`.
44
+
45
+ @example
46
+ ```
47
+ type A = SplitArrayByIndex<[1, 2, 3, 4], 2>;
48
+ // type A = [[1, 2], [3, 4]];
49
+
50
+ type B = SplitArrayByIndex<[1, 2, 3, 4], 0>;
51
+ // type B = [[], [1, 2, 3, 4]];
52
+ ```
53
+ */
54
+ type SplitArrayByIndex<T extends UnknownArray, SplitIndex extends number> =
55
+ SplitIndex extends 0
56
+ ? [[], T]
57
+ : number extends T['length']
58
+ ? SplitVariableArrayByIndex<T, SplitIndex>
59
+ : SplitFixedArrayByIndex<T, SplitIndex>;
60
+
61
+ /**
62
+ Creates a new array type by adding or removing elements at a specified index range in the original array.
63
+
64
+ Use-case: Replace or insert items in an array type.
65
+
66
+ Like [`Array#splice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) but for types.
67
+
68
+ @example
69
+ ```
70
+ type SomeMonths0 = ['January', 'April', 'June'];
71
+ type Mouths0 = ArraySplice<SomeMonths0, 1, 0, ['Feb', 'March']>;
72
+ //=> type Mouths0 = ['January', 'Feb', 'March', 'April', 'June'];
73
+
74
+ type SomeMonths1 = ['January', 'April', 'June'];
75
+ type Mouths1 = ArraySplice<SomeMonths1, 1, 1>;
76
+ //=> type Mouths1 = ['January', 'June'];
77
+
78
+ type SomeMonths2 = ['January', 'Foo', 'April'];
79
+ type Mouths2 = ArraySplice<SomeMonths2, 1, 1, ['Feb', 'March']>;
80
+ //=> type Mouths2 = ['January', 'Feb', 'March', 'April'];
81
+ ```
82
+
83
+ @category Array
84
+ */
85
+ export type ArraySplice<
86
+ T extends UnknownArray,
87
+ Start extends number,
88
+ DeleteCount extends number,
89
+ Items extends UnknownArray = [],
90
+ > =
91
+ SplitArrayByIndex<T, Start> extends [infer U extends UnknownArray, infer V extends UnknownArray]
92
+ ? SplitArrayByIndex<V, DeleteCount> extends [infer _Deleted extends UnknownArray, infer X extends UnknownArray]
93
+ ? [...U, ...Items, ...X]
94
+ : never // Should never happen
95
+ : never; // Should never happen
@@ -2,9 +2,11 @@ import type {Primitive} from './primitive';
2
2
  import type {Simplify} from './simplify';
3
3
  import type {Trim} from './trim';
4
4
  import type {IsAny} from './is-any';
5
+ import type {IsLiteral} from './is-literal';
5
6
  import type {UnknownRecord} from './unknown-record';
6
7
  import type {IsNever} from './is-never';
7
8
  import type {UnknownArray} from './unknown-array';
9
+ import type {IsEqual} from './is-equal';
8
10
 
9
11
  // TODO: Remove for v5.
10
12
  export type {UnknownRecord} from './unknown-record';
@@ -357,6 +359,11 @@ IsPrimitive<Object>
357
359
  */
358
360
  export type IsPrimitive<T> = [T] extends [Primitive] ? true : false;
359
361
 
362
+ /**
363
+ Utility type to retrieve only literal keys from type.
364
+ */
365
+ export type LiteralKeyOf<T> = keyof {[K in keyof T as IsLiteral<K> extends true ? K : never]-?: never};
366
+
360
367
  /**
361
368
  Returns the static, fixed-length portion of the given array, excluding variable-length parts.
362
369
 
@@ -471,3 +478,102 @@ type InternalIsUnion<T, U = T> =
471
478
  ? boolean extends Result ? true
472
479
  : Result
473
480
  : never; // Should never happen
481
+
482
+ /**
483
+ Set the given array to readonly if `IsReadonly` is `true`, otherwise set the given array to normal, then return the result.
484
+
485
+ @example
486
+ ```
487
+ type ReadonlyArray = readonly string[];
488
+ type NormalArray = string[];
489
+
490
+ type ReadonlyResult = SetArrayAccess<NormalArray, true>;
491
+ //=> readonly string[]
492
+
493
+ type NormalResult = SetArrayAccess<ReadonlyArray, false>;
494
+ //=> string[]
495
+ ```
496
+ */
497
+ export type SetArrayAccess<T extends UnknownArray, IsReadonly extends boolean> =
498
+ T extends readonly [...infer U] ?
499
+ IsReadonly extends true
500
+ ? readonly [...U]
501
+ : [...U]
502
+ : T;
503
+
504
+ /**
505
+ Returns whether the given array `T` is readonly.
506
+ */
507
+ export type IsArrayReadonly<T extends UnknownArray> = T extends unknown[] ? false : true;
508
+
509
+ /**
510
+ Returns the result of `A >= B`.
511
+
512
+ @example
513
+ ```
514
+ type A = GTE<15, 10>;
515
+ //=> true
516
+
517
+ type B = GTE<10, 15>;
518
+ //=> false
519
+
520
+ type C = GTE<10, 10>;
521
+ //=> true
522
+ ```
523
+ */
524
+ export type GTE<A extends number, B extends number> =
525
+ BuildTuple<A> extends [...infer _, ...BuildTuple<B>]
526
+ ? true
527
+ : false;
528
+
529
+ /**
530
+ Returns the result of `A > B`
531
+
532
+ @example
533
+ ```
534
+ type A = GT<15, 10>;
535
+ //=> true
536
+
537
+ type B = GT<10, 15>;
538
+ //=> false
539
+ */
540
+ export type GT<A extends number, B extends number> =
541
+ IsEqual<A, B> extends true
542
+ ? false
543
+ : GTE<A, B>;
544
+
545
+ /**
546
+ Get the exact version of the given `Key` in the given object `T`.
547
+
548
+ Use-case: You known that a number key (e.g. 10) is in an object, but you don't know how it is defined in the object, as a string or as a number (e.g. 10 or '10'). You can use this type to get the exact version of the key. See the example.
549
+
550
+ @example
551
+ ```
552
+ type Object = {
553
+ 0: number;
554
+ '1': string;
555
+ };
556
+
557
+ type Key1 = ExactKey<Object, '0'>;
558
+ //=> 0
559
+ type Key2 = ExactKey<Object, 0>;
560
+ //=> 0
561
+
562
+ type Key3 = ExactKey<Object, '1'>;
563
+ //=> '1'
564
+ type Key4 = ExactKey<Object, 1>;
565
+ //=> '1'
566
+ ```
567
+
568
+ @category Object
569
+ */
570
+ export type ExactKey<T extends object, Key extends PropertyKey> =
571
+ Key extends keyof T
572
+ ? Key
573
+ : ToString<Key> extends keyof T
574
+ ? ToString<Key>
575
+ : Key extends `${infer NumberKey extends number}`
576
+ ? NumberKey extends keyof T
577
+ ? NumberKey
578
+ : never
579
+ : never;
@@ -0,0 +1,136 @@
1
+ import type {ArraySplice} from './array-splice';
2
+ import type {ExactKey, IsArrayReadonly, NonRecursiveType, SetArrayAccess, ToString} from './internal';
3
+ import type {IsEqual} from './is-equal';
4
+ import type {SimplifyDeep} from './merge-deep';
5
+ import type {Paths} from './paths';
6
+ import type {SharedUnionFieldsDeep} from './shared-union-fields-deep';
7
+ import type {UnknownArray} from './unknown-array';
8
+
9
+ /**
10
+ Omit properties from a deeply-nested object.
11
+
12
+ It supports recursing into arrays.
13
+
14
+ It supports removing specific items from an array, replacing each removed item with unknown at the specified index.
15
+
16
+ Use-case: Remove unneeded parts of complex objects.
17
+
18
+ Use [`Omit`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys) if you only need one level deep.
19
+
20
+ @example
21
+ ```
22
+ import type {OmitDeep} from 'type-fest';
23
+
24
+ type Info = {
25
+ userInfo: {
26
+ name: string;
27
+ uselessInfo: {
28
+ foo: string;
29
+ };
30
+ };
31
+ };
32
+
33
+ type UsefulInfo = OmitDeep<Info, 'userInfo.uselessInfo'>;
34
+ // type UsefulInfo = {
35
+ // userInfo: {
36
+ // name: string;
37
+ // };
38
+
39
+ // Supports array
40
+ type A = OmitDeep<[1, 'foo', 2], 1>;
41
+ // type A = [1, unknown, 2];
42
+
43
+ // Supports recursing into array
44
+
45
+ type Info1 = {
46
+ address: [
47
+ {
48
+ street: string
49
+ },
50
+ {
51
+ street2: string,
52
+ foo: string
53
+ };
54
+ ];
55
+ }
56
+ type AddressInfo = OmitDeep<Info1, 'address.1.foo'>;
57
+ // type AddressInfo = {
58
+ // address: [
59
+ // {
60
+ // street: string;
61
+ // },
62
+ // {
63
+ // street2: string;
64
+ // };
65
+ // ];
66
+ // };
67
+ ```
68
+
69
+ @category Object
70
+ @category Array
71
+ */
72
+ export type OmitDeep<T, PathUnion extends Paths<T>> =
73
+ SimplifyDeep<
74
+ SharedUnionFieldsDeep<
75
+ {[P in PathUnion]: OmitDeepWithOnePath<T, P>}[PathUnion]
76
+ >
77
+ >;
78
+
79
+ /**
80
+ Omit one path from the given object/array.
81
+ */
82
+ type OmitDeepWithOnePath<T, Path extends string | number> =
83
+ T extends NonRecursiveType
84
+ ? T
85
+ : T extends UnknownArray ? SetArrayAccess<OmitDeepArrayWithOnePath<T, Path>, IsArrayReadonly<T>>
86
+ : T extends object ? OmitDeepObjectWithOnePath<T, Path>
87
+ : T;
88
+
89
+ /**
90
+ Omit one path from the given object.
91
+ */
92
+ type OmitDeepObjectWithOnePath<ObjectT extends object, P extends string | number> =
93
+ P extends `${infer RecordKeyInPath}.${infer SubPath}`
94
+ ? {
95
+ [Key in keyof ObjectT]:
96
+ IsEqual<RecordKeyInPath, ToString<Key>> extends true
97
+ ? ExactKey<ObjectT, Key> extends infer RealKey
98
+ ? RealKey extends keyof ObjectT
99
+ ? OmitDeepWithOnePath<ObjectT[RealKey], SubPath>
100
+ : ObjectT[Key]
101
+ : ObjectT[Key]
102
+ : ObjectT[Key]
103
+ }
104
+ : ExactKey<ObjectT, P> extends infer Key
105
+ ? Key extends PropertyKey
106
+ ? Omit<ObjectT, Key>
107
+ : ObjectT
108
+ : ObjectT;
109
+
110
+ /**
111
+ Omit one path from from the given array.
112
+
113
+ It replaces the item to `unknown` at the given index.
114
+
115
+ @example
116
+ ```
117
+ type A = OmitDeepArrayWithOnePath<[10, 20, 30, 40], 2>;
118
+ //=> type A = [10, 20, unknown, 40];
119
+ ```
120
+ */
121
+ type OmitDeepArrayWithOnePath<ArrayType extends UnknownArray, P extends string | number> =
122
+ // Handle paths that are `${number}.${string}`
123
+ P extends `${infer ArrayIndex extends number}.${infer SubPath}`
124
+ // If `ArrayIndex` is equal to `number`
125
+ ? number extends ArrayIndex
126
+ ? Array<OmitDeepWithOnePath<NonNullable<ArrayType[number]>, SubPath>>
127
+ // If `ArrayIndex` is a number literal
128
+ : ArraySplice<ArrayType, ArrayIndex, 1, [OmitDeepWithOnePath<NonNullable<ArrayType[ArrayIndex]>, SubPath>]>
129
+ // If the path is equal to `number`
130
+ : P extends `${infer ArrayIndex extends number}`
131
+ // If `ArrayIndex` is `number`
132
+ ? number extends ArrayIndex
133
+ ? []
134
+ // If `ArrayIndex` is a number literal
135
+ : ArraySplice<ArrayType, ArrayIndex, 1, [unknown]>
136
+ : never;
@@ -4,9 +4,7 @@ export type TagContainer<Token> = {
4
4
  readonly [tag]: Token;
5
5
  };
6
6
 
7
- type MultiTagContainer<Token extends PropertyKey> = {
8
- readonly [tag]: {[K in Token]: void};
9
- };
7
+ type Tag<Token extends PropertyKey, TagMetadata> = TagContainer<{[K in Token]: TagMetadata}>;
10
8
 
11
9
  /**
12
10
  Attach a "tag" to an arbitrary type. This allows you to create distinct types, that aren't assignable to one another, for runtime values that would otherwise have the same type. (See examples.)
@@ -113,19 +111,26 @@ type WillWork = UnwrapOpaque<Tagged<number, 'AccountNumber'>>; // number
113
111
  @category Type
114
112
  */
115
113
  export type UnwrapOpaque<OpaqueType extends TagContainer<unknown>> =
116
- OpaqueType extends MultiTagContainer<string | number | symbol>
114
+ OpaqueType extends Tag<PropertyKey, any>
117
115
  ? RemoveAllTags<OpaqueType>
118
116
  : OpaqueType extends Opaque<infer Type, OpaqueType[typeof tag]>
119
117
  ? Type
120
118
  : OpaqueType;
121
119
 
122
120
  /**
123
- Attach a "tag" to an arbitrary type. This allows you to create distinct types, that aren't assignable to one another, for runtime values that would otherwise have the same type. (See examples.)
121
+ Attach a "tag" to an arbitrary type. This allows you to create distinct types, that aren't assignable to one another, for distinct concepts in your program that should not be interchangeable, even if their runtime values have the same type. (See examples.)
124
122
 
125
123
  A type returned by `Tagged` can be passed to `Tagged` again, to create a type with multiple tags.
126
124
 
127
125
  [Read more about tagged types.](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d)
128
126
 
127
+ A tag's name is usually a string (and must be a string, number, or symbol), but each application of a tag can also contain an arbitrary type as its "metadata". See {@link GetTagMetadata} for examples and explanation.
128
+
129
+ A type `A` returned by `Tagged` is assignable to another type `B` returned by `Tagged` if and only if:
130
+ - the underlying (untagged) type of `A` is assignable to the underlying type of `B`;
131
+ - `A` contains at least all the tags `B` has;
132
+ - and the metadata type for each of `A`'s tags is assignable to the metadata type of `B`'s corresponding tag.
133
+
129
134
  There have been several discussions about adding similar features to TypeScript. Unfortunately, nothing has (yet) moved forward:
130
135
  - [Microsoft/TypeScript#202](https://github.com/microsoft/TypeScript/issues/202)
131
136
  - [Microsoft/TypeScript#4895](https://github.com/microsoft/TypeScript/issues/4895)
@@ -151,21 +156,62 @@ function getMoneyForAccount(accountNumber: AccountNumber): AccountBalance {
151
156
  getMoneyForAccount(createAccountNumber());
152
157
 
153
158
  // But this won't, because it has to be explicitly passed as an `AccountNumber` type!
159
+ // Critically, you could not accidentally use an `AccountBalance` as an `AccountNumber`.
154
160
  getMoneyForAccount(2);
155
161
 
156
- // You can use opaque values like they aren't opaque too.
157
- const accountNumber = createAccountNumber();
162
+ // You can also use tagged values like their underlying, untagged type.
163
+ // I.e., this will compile successfully because an `AccountNumber` can be used as a regular `number`.
164
+ // In this sense, the underlying base type is not hidden, which differentiates tagged types from opaque types in other languages.
165
+ const accountNumber = createAccountNumber() + 2;
166
+ ```
158
167
 
159
- // This will compile successfully.
160
- const newAccountNumber = accountNumber + 2;
168
+ @example
169
+ ```
170
+ import type {Tagged} from 'type-fest';
171
+
172
+ // You can apply multiple tags to a type by using `Tagged` repeatedly.
173
+ type Url = Tagged<string, 'URL'>;
174
+ type SpecialCacheKey = Tagged<Url, 'SpecialCacheKey'>;
175
+
176
+ // You can also pass a union of tag names, so this is equivalent to the above, although it doesn't give you the ability to assign distinct metadata to each tag.
177
+ type SpecialCacheKey2 = Tagged<string, 'URL' | 'SpecialCacheKey'>;
178
+ ```
179
+
180
+ @category Type
181
+ */
182
+ export type Tagged<Type, TagName extends PropertyKey, TagMetadata = never> = Type & Tag<TagName, TagMetadata>;
183
+
184
+ /**
185
+ Given a type and a tag name, returns the metadata associated with that tag on that type.
186
+
187
+ In the example below, one could use `Tagged<string, 'JSON'>` to represent "a string that is valid JSON". That type might be useful -- for instance, it communicates that the value can be safely passed to `JSON.parse` without it throwing an exception. However, it doesn't indicate what type of value will be produced on parse (which is sometimes known). `JsonOf<T>` solves this; it represents "a string that is valid JSON and that, if parsed, would produce a value of type T". The type T is held in the metadata associated with the `'JSON'` tag.
188
+
189
+ This article explains more about [how tag metadata works and when it can be useful](https://medium.com/@ethanresnick/advanced-typescript-tagged-types-improved-with-type-level-metadata-5072fc125fcf).
190
+
191
+ @example
192
+ ```
193
+ import type {Tagged} from 'type-fest';
194
+
195
+ type JsonOf<T> = Tagged<string, 'JSON', T>;
196
+
197
+ function stringify<T>(it: T) {
198
+ return JSON.stringify(it) as JsonOf<T>;
199
+ }
200
+
201
+ function parse<T extends JsonOf<unknown>>(it: T) {
202
+ return JSON.parse(it) as GetTagMetadata<T, 'JSON'>;
203
+ }
204
+
205
+ const x = stringify({ hello: 'world' });
206
+ const parsed = parse(x); // The type of `parsed` is { hello: string }
161
207
  ```
162
208
 
163
209
  @category Type
164
210
  */
165
- export type Tagged<Type, Tag extends PropertyKey> = Type & MultiTagContainer<Tag>;
211
+ export type GetTagMetadata<Type extends Tag<TagName, unknown>, TagName extends PropertyKey> = Type[typeof tag][TagName];
166
212
 
167
213
  /**
168
- Revert a tagged type back to its original type by removing the readonly `[tag]`.
214
+ Revert a tagged type back to its original type by removing all tags.
169
215
 
170
216
  Why is this necessary?
171
217
 
@@ -192,14 +238,13 @@ type WontWork = UnwrapTagged<string>;
192
238
 
193
239
  @category Type
194
240
  */
195
- export type UnwrapTagged<TaggedType extends MultiTagContainer<PropertyKey>> =
241
+ export type UnwrapTagged<TaggedType extends Tag<PropertyKey, any>> =
196
242
  RemoveAllTags<TaggedType>;
197
243
 
198
- type RemoveAllTags<T> = T extends MultiTagContainer<infer ExistingTags>
244
+ type RemoveAllTags<T> = T extends Tag<PropertyKey, any>
199
245
  ? {
200
- [ThisTag in ExistingTags]:
201
- T extends Tagged<infer Type, ThisTag>
246
+ [ThisTag in keyof T[typeof tag]]: T extends Tagged<infer Type, ThisTag, T[typeof tag][ThisTag]>
202
247
  ? RemoveAllTags<Type>
203
248
  : never
204
- }[ExistingTags]
249
+ }[keyof T[typeof tag]]
205
250
  : T;
@@ -1,4 +1,5 @@
1
- import type {BuiltIns} from './internal';
1
+ import type {IfUnknown} from './if-unknown';
2
+ import type {BuiltIns, LiteralKeyOf} from './internal';
2
3
  import type {Merge} from './merge';
3
4
 
4
5
  /**
@@ -47,8 +48,8 @@ const testSettings: PartialOnUndefinedDeep<Settings> = {
47
48
  @category Object
48
49
  */
49
50
  export type PartialOnUndefinedDeep<T, Options extends PartialOnUndefinedDeepOptions = {}> = T extends Record<any, any> | undefined
50
- ? {[KeyType in keyof T as undefined extends T[KeyType] ? KeyType : never]?: PartialOnUndefinedDeepValue<T[KeyType], Options>} extends infer U // Make a partial type with all value types accepting undefined (and set them optional)
51
- ? Merge<{[KeyType in keyof T as KeyType extends keyof U ? never : KeyType]: PartialOnUndefinedDeepValue<T[KeyType], Options>}, U> // Join all remaining keys not treated in U
51
+ ? {[KeyType in keyof T as undefined extends T[KeyType] ? IfUnknown<T[KeyType], never, KeyType> : never]?: PartialOnUndefinedDeepValue<T[KeyType], Options>} extends infer U // Make a partial type with all value types accepting undefined (and set them optional)
52
+ ? Merge<{[KeyType in keyof T as KeyType extends LiteralKeyOf<U> ? never : KeyType]: PartialOnUndefinedDeepValue<T[KeyType], Options>}, U> // Join all remaining keys not treated in U
52
53
  : never // Should not happen
53
54
  : T;
54
55
 
@@ -1,34 +1,7 @@
1
- import type {NonRecursiveType, UnionMin, UnionMax, TupleLength, StaticPartOfArray, VariablePartOfArray, IsUnion} from './internal';
1
+ import type {NonRecursiveType, UnionMin, UnionMax, TupleLength, StaticPartOfArray, VariablePartOfArray, IsUnion, IsArrayReadonly, SetArrayAccess} from './internal';
2
2
  import type {IsNever} from './is-never';
3
3
  import type {UnknownArray} from './unknown-array';
4
4
 
5
- /**
6
- Set the given array to readonly if `IsReadonly` is `true`, otherwise set the given array to normal, then return the result.
7
-
8
- @example
9
- ```
10
- type ReadonlyArray = readonly string[];
11
- type NormalArray = string[];
12
-
13
- type ReadonlyResult = SetArrayAccess<NormalArray, true>;
14
- //=> readonly string[]
15
-
16
- type NormalResult = SetArrayAccess<ReadonlyArray, false>;
17
- //=> string[]
18
- ```
19
- */
20
- type SetArrayAccess<T extends UnknownArray, IsReadonly extends boolean> =
21
- T extends readonly [...infer U] ?
22
- IsReadonly extends true
23
- ? readonly [...U]
24
- : [...U]
25
- : T;
26
-
27
- /**
28
- Returns whether the given array `T` is readonly.
29
- */
30
- type IsArrayReadonly<T extends UnknownArray> = T extends unknown[] ? false : true;
31
-
32
5
  /**
33
6
  SharedUnionFieldsDeep options.
34
7