@depup/type-fest 5.4.4-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/README.md +25 -0
  2. package/index.d.ts +211 -0
  3. package/license-cc0 +121 -0
  4. package/license-mit +9 -0
  5. package/package.json +85 -0
  6. package/readme.md +1052 -0
  7. package/source/all-extend.d.ts +120 -0
  8. package/source/all-union-fields.d.ts +91 -0
  9. package/source/and.d.ts +81 -0
  10. package/source/array-element.d.ts +46 -0
  11. package/source/array-indices.d.ts +25 -0
  12. package/source/array-reverse.d.ts +84 -0
  13. package/source/array-slice.d.ts +132 -0
  14. package/source/array-splice.d.ts +104 -0
  15. package/source/array-tail.d.ts +70 -0
  16. package/source/array-values.d.ts +24 -0
  17. package/source/arrayable.d.ts +31 -0
  18. package/source/async-return-type.d.ts +28 -0
  19. package/source/asyncify.d.ts +25 -0
  20. package/source/basic.d.ts +38 -0
  21. package/source/camel-case.d.ts +92 -0
  22. package/source/camel-cased-properties-deep.d.ts +99 -0
  23. package/source/camel-cased-properties.d.ts +45 -0
  24. package/source/characters.d.ts +67 -0
  25. package/source/conditional-except.d.ts +47 -0
  26. package/source/conditional-keys.d.ts +63 -0
  27. package/source/conditional-pick-deep.d.ts +120 -0
  28. package/source/conditional-pick.d.ts +46 -0
  29. package/source/conditional-simplify-deep.d.ts +73 -0
  30. package/source/conditional-simplify.d.ts +50 -0
  31. package/source/delimiter-case.d.ts +77 -0
  32. package/source/delimiter-cased-properties-deep.d.ts +108 -0
  33. package/source/delimiter-cased-properties.d.ts +48 -0
  34. package/source/distributed-omit.d.ts +96 -0
  35. package/source/distributed-pick.d.ts +92 -0
  36. package/source/empty-object.d.ts +51 -0
  37. package/source/entries.d.ts +64 -0
  38. package/source/entry.d.ts +67 -0
  39. package/source/exact.d.ts +73 -0
  40. package/source/except.d.ts +112 -0
  41. package/source/exclude-rest-element.d.ts +40 -0
  42. package/source/exclude-strict.d.ts +51 -0
  43. package/source/exclusify-union.d.ts +147 -0
  44. package/source/extends-strict.d.ts +44 -0
  45. package/source/extract-rest-element.d.ts +30 -0
  46. package/source/extract-strict.d.ts +51 -0
  47. package/source/find-global-type.d.ts +68 -0
  48. package/source/fixed-length-array.d.ts +97 -0
  49. package/source/get.d.ts +227 -0
  50. package/source/global-this.d.ts +24 -0
  51. package/source/globals/index.d.ts +3 -0
  52. package/source/globals/observable-like.d.ts +78 -0
  53. package/source/greater-than-or-equal.d.ts +30 -0
  54. package/source/greater-than.d.ts +58 -0
  55. package/source/has-optional-keys.d.ts +23 -0
  56. package/source/has-readonly-keys.d.ts +23 -0
  57. package/source/has-required-keys.d.ts +61 -0
  58. package/source/has-writable-keys.d.ts +23 -0
  59. package/source/if-any.d.ts +28 -0
  60. package/source/if-empty-object.d.ts +30 -0
  61. package/source/if-never.d.ts +28 -0
  62. package/source/if-null.d.ts +28 -0
  63. package/source/if-unknown.d.ts +28 -0
  64. package/source/if.d.ts +102 -0
  65. package/source/includes.d.ts +24 -0
  66. package/source/int-closed-range.d.ts +47 -0
  67. package/source/int-range.d.ts +69 -0
  68. package/source/internal/array.d.ts +151 -0
  69. package/source/internal/characters.d.ts +65 -0
  70. package/source/internal/enforce-optional.d.ts +49 -0
  71. package/source/internal/index.d.ts +11 -0
  72. package/source/internal/keys.d.ts +100 -0
  73. package/source/internal/numeric.d.ts +151 -0
  74. package/source/internal/object.d.ts +292 -0
  75. package/source/internal/string.d.ts +202 -0
  76. package/source/internal/tuple.d.ts +79 -0
  77. package/source/internal/type.d.ts +164 -0
  78. package/source/invariant-of.d.ts +85 -0
  79. package/source/is-any.d.ts +31 -0
  80. package/source/is-equal.d.ts +42 -0
  81. package/source/is-float.d.ts +43 -0
  82. package/source/is-integer.d.ts +60 -0
  83. package/source/is-literal.d.ts +315 -0
  84. package/source/is-lowercase.d.ts +38 -0
  85. package/source/is-never.d.ts +56 -0
  86. package/source/is-null.d.ts +22 -0
  87. package/source/is-nullable.d.ts +30 -0
  88. package/source/is-optional-key-of.d.ts +51 -0
  89. package/source/is-optional.d.ts +28 -0
  90. package/source/is-readonly-key-of.d.ts +55 -0
  91. package/source/is-required-key-of.d.ts +51 -0
  92. package/source/is-tuple.d.ts +92 -0
  93. package/source/is-undefined.d.ts +22 -0
  94. package/source/is-union.d.ts +40 -0
  95. package/source/is-unknown.d.ts +43 -0
  96. package/source/is-uppercase.d.ts +38 -0
  97. package/source/is-writable-key-of.d.ts +51 -0
  98. package/source/iterable-element.d.ts +66 -0
  99. package/source/join.d.ts +79 -0
  100. package/source/json-value.d.ts +33 -0
  101. package/source/jsonifiable.d.ts +37 -0
  102. package/source/jsonify.d.ts +127 -0
  103. package/source/kebab-case.d.ts +46 -0
  104. package/source/kebab-cased-properties-deep.d.ts +65 -0
  105. package/source/kebab-cased-properties.d.ts +42 -0
  106. package/source/key-as-string.d.ts +27 -0
  107. package/source/keys-of-union.d.ts +44 -0
  108. package/source/last-array-element.d.ts +36 -0
  109. package/source/less-than-or-equal.d.ts +24 -0
  110. package/source/less-than.d.ts +28 -0
  111. package/source/literal-to-primitive-deep.d.ts +71 -0
  112. package/source/literal-to-primitive.d.ts +38 -0
  113. package/source/literal-union.d.ts +39 -0
  114. package/source/merge-deep.d.ts +495 -0
  115. package/source/merge-exclusive.d.ts +45 -0
  116. package/source/merge.d.ts +62 -0
  117. package/source/multidimensional-array.d.ts +38 -0
  118. package/source/multidimensional-readonly-array.d.ts +38 -0
  119. package/source/non-empty-object.d.ts +38 -0
  120. package/source/non-empty-string.d.ts +32 -0
  121. package/source/non-empty-tuple.d.ts +24 -0
  122. package/source/numeric.d.ts +226 -0
  123. package/source/object-merge.d.ts +194 -0
  124. package/source/omit-deep.d.ts +154 -0
  125. package/source/omit-index-signature.d.ts +98 -0
  126. package/source/opaque.d.ts +3 -0
  127. package/source/optional-keys-of.d.ts +46 -0
  128. package/source/or.d.ts +89 -0
  129. package/source/override-properties.d.ts +43 -0
  130. package/source/package-json.d.ts +710 -0
  131. package/source/partial-deep.d.ts +155 -0
  132. package/source/partial-on-undefined-deep.d.ts +81 -0
  133. package/source/pascal-case.d.ts +51 -0
  134. package/source/pascal-cased-properties-deep.d.ts +72 -0
  135. package/source/pascal-cased-properties.d.ts +42 -0
  136. package/source/paths.d.ts +241 -0
  137. package/source/pick-deep.d.ts +152 -0
  138. package/source/pick-index-signature.d.ts +52 -0
  139. package/source/primitive.d.ts +15 -0
  140. package/source/promisable.d.ts +27 -0
  141. package/source/readonly-deep.d.ts +116 -0
  142. package/source/readonly-keys-of.d.ts +38 -0
  143. package/source/readonly-tuple.d.ts +34 -0
  144. package/source/remove-prefix.d.ts +132 -0
  145. package/source/replace.d.ts +87 -0
  146. package/source/require-all-or-none.d.ts +54 -0
  147. package/source/require-at-least-one.d.ts +50 -0
  148. package/source/require-exactly-one.d.ts +48 -0
  149. package/source/require-one-or-none.d.ts +49 -0
  150. package/source/required-deep.d.ts +76 -0
  151. package/source/required-keys-of.d.ts +38 -0
  152. package/source/schema.d.ts +119 -0
  153. package/source/screaming-snake-case.d.ts +30 -0
  154. package/source/set-field-type.d.ts +67 -0
  155. package/source/set-non-nullable-deep.d.ts +85 -0
  156. package/source/set-non-nullable.d.ts +41 -0
  157. package/source/set-optional.d.ts +46 -0
  158. package/source/set-parameter-type.d.ts +125 -0
  159. package/source/set-readonly.d.ts +44 -0
  160. package/source/set-required-deep.d.ts +64 -0
  161. package/source/set-required.d.ts +79 -0
  162. package/source/set-return-type.d.ts +31 -0
  163. package/source/shared-union-fields-deep.d.ts +180 -0
  164. package/source/shared-union-fields.d.ts +79 -0
  165. package/source/simplify-deep.d.ts +117 -0
  166. package/source/simplify.d.ts +61 -0
  167. package/source/single-key-object.d.ts +28 -0
  168. package/source/snake-case.d.ts +47 -0
  169. package/source/snake-cased-properties-deep.d.ts +65 -0
  170. package/source/snake-cased-properties.d.ts +42 -0
  171. package/source/split-on-rest-element.d.ts +106 -0
  172. package/source/split.d.ts +90 -0
  173. package/source/spread.d.ts +82 -0
  174. package/source/string-repeat.d.ts +49 -0
  175. package/source/string-slice.d.ts +39 -0
  176. package/source/stringified.d.ts +25 -0
  177. package/source/structured-cloneable.d.ts +89 -0
  178. package/source/subtract.d.ts +86 -0
  179. package/source/sum.d.ts +81 -0
  180. package/source/tagged-union.d.ts +53 -0
  181. package/source/tagged.d.ts +263 -0
  182. package/source/trim.d.ts +29 -0
  183. package/source/tsconfig-json.d.ts +1324 -0
  184. package/source/tuple-of.d.ts +80 -0
  185. package/source/tuple-to-object.d.ts +47 -0
  186. package/source/tuple-to-union.d.ts +54 -0
  187. package/source/typed-array.d.ts +19 -0
  188. package/source/undefined-on-partial-deep.d.ts +83 -0
  189. package/source/union-to-intersection.d.ts +35 -0
  190. package/source/union-to-tuple.d.ts +58 -0
  191. package/source/unknown-array.d.ts +27 -0
  192. package/source/unknown-map.d.ts +26 -0
  193. package/source/unknown-record.d.ts +33 -0
  194. package/source/unknown-set.d.ts +26 -0
  195. package/source/unwrap-partial.d.ts +33 -0
  196. package/source/value-of.d.ts +24 -0
  197. package/source/words.d.ts +122 -0
  198. package/source/writable-deep.d.ts +84 -0
  199. package/source/writable-keys-of.d.ts +34 -0
  200. package/source/writable.d.ts +72 -0
  201. package/source/xor.d.ts +83 -0
@@ -0,0 +1,39 @@
1
+ import type {Join} from './join.d.ts';
2
+ import type {ArraySlice} from './array-slice.d.ts';
3
+ import type {StringToArray} from './internal/index.d.ts';
4
+
5
+ /**
6
+ Returns a string slice of a given range, just like `String#slice()`.
7
+
8
+ @see {ArraySlice}
9
+
10
+ @example
11
+ ```
12
+ import type {StringSlice} from 'type-fest';
13
+
14
+ type A = StringSlice<'abcde', 0, 2>;
15
+ //=> 'ab'
16
+
17
+ type B = StringSlice<'abcde', 1>;
18
+ //=> 'bcde'
19
+
20
+ type C = StringSlice<'abcde', 0, -1>;
21
+ //=> 'abcd'
22
+
23
+ type D = StringSlice<'abcde', -2, -1>;
24
+ //=> 'd'
25
+ ```
26
+
27
+ @category String
28
+ */
29
+ export type StringSlice<
30
+ S extends string,
31
+ Start extends number = never,
32
+ End extends number = never,
33
+ > = string extends S
34
+ ? string
35
+ : ArraySlice<StringToArray<S>, Start, End> extends infer R extends readonly string[]
36
+ ? Join<R, ''>
37
+ : never;
38
+
39
+ export {};
@@ -0,0 +1,25 @@
1
+ /**
2
+ Create a type with the keys of the given type changed to `string` type.
3
+
4
+ Use-case: Changing interface values to strings in order to use them in a form model.
5
+
6
+ @example
7
+ ```
8
+ import type {Stringified} from 'type-fest';
9
+
10
+ type Car = {
11
+ model: string;
12
+ speed: number;
13
+ };
14
+
15
+ const carForm: Stringified<Car> = {
16
+ model: 'Foo',
17
+ speed: '101',
18
+ };
19
+ ```
20
+
21
+ @category Object
22
+ */
23
+ export type Stringified<ObjectType> = {[KeyType in keyof ObjectType]: string};
24
+
25
+ export {};
@@ -0,0 +1,89 @@
1
+ import type {TypedArray} from './typed-array.d.ts';
2
+ import type {FindGlobalInstanceType} from './find-global-type.d.ts';
3
+
4
+ type StructuredCloneablePrimitive =
5
+ | string
6
+ | number
7
+ | bigint
8
+ | boolean
9
+ | null
10
+ | undefined
11
+ | Boolean
12
+ | Number
13
+ | String;
14
+
15
+ type StructuredCloneableData =
16
+ | ArrayBuffer
17
+ | DataView
18
+ | Date
19
+ | Error
20
+ | RegExp
21
+ | TypedArray
22
+ | FindGlobalInstanceType<
23
+ // DOM or Node types
24
+ | 'Blob'
25
+ | 'File'
26
+ // DOM exclusive types
27
+ | 'AudioData'
28
+ | 'CropTarget'
29
+ | 'CryptoKey'
30
+ | 'DOMException'
31
+ | 'DOMMatrix'
32
+ | 'DOMMatrixReadOnly'
33
+ | 'DOMPoint'
34
+ | 'DOMPointReadOnly'
35
+ | 'DOMQuad'
36
+ | 'DOMRect'
37
+ | 'DOMRectReadOnly'
38
+ | 'FileList'
39
+ | 'FileSystemDirectoryHandle'
40
+ | 'FileSystemFileHandle'
41
+ | 'FileSystemHandle'
42
+ | 'GPUCompilationInfo'
43
+ | 'GPUCompilationMessage'
44
+ | 'ImageBitmap'
45
+ | 'ImageData'
46
+ | 'RTCCertificate'
47
+ | 'VideoFrame'
48
+ >;
49
+
50
+ type StructuredCloneableCollection =
51
+ | readonly StructuredCloneable[]
52
+ | {readonly [key: string]: StructuredCloneable; readonly [key: number]: StructuredCloneable}
53
+ | ReadonlyMap<StructuredCloneable, StructuredCloneable>
54
+ | ReadonlySet<StructuredCloneable>;
55
+
56
+ /**
57
+ Matches a value that can be losslessly cloned using `structuredClone`.
58
+
59
+ Note:
60
+ - Custom error types will be cloned as the base `Error` type
61
+
62
+ @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
63
+
64
+ @example
65
+ ```
66
+ import type {StructuredCloneable} from 'type-fest';
67
+
68
+ class CustomClass {}
69
+
70
+ const error = {
71
+ custom: new CustomClass(),
72
+ // @ts-expect-error
73
+ } satisfies StructuredCloneable;
74
+
75
+ const good = {
76
+ number: 3,
77
+ date: new Date(),
78
+ map: new Map<string, number>(),
79
+ } satisfies StructuredCloneable;
80
+
81
+ const clonedGood = structuredClone(good);
82
+ //=> {number: number; date: Date; map: Map<string, number>}
83
+ ```
84
+
85
+ @category Structured clone
86
+ */
87
+ export type StructuredCloneable = StructuredCloneablePrimitive | StructuredCloneableData | StructuredCloneableCollection;
88
+
89
+ export {};
@@ -0,0 +1,86 @@
1
+ import type {NumberAbsolute, ReverseSign} from './internal/index.d.ts';
2
+ import type {PositiveInfinity, NegativeInfinity, IsNegative} from './numeric.d.ts';
3
+ import type {LessThan} from './less-than.d.ts';
4
+ import type {TupleOf} from './tuple-of.d.ts';
5
+
6
+ /**
7
+ Returns the difference between two numbers.
8
+
9
+ Note:
10
+ - A or B can only support `-999` ~ `999`.
11
+
12
+ @example
13
+ ```
14
+ import type {Subtract, PositiveInfinity} from 'type-fest';
15
+
16
+ type A = Subtract<333, 222>;
17
+ //=> 111
18
+
19
+ type B = Subtract<111, -222>;
20
+ //=> 333
21
+
22
+ type C = Subtract<-111, 222>;
23
+ //=> -333
24
+
25
+ type D = Subtract<18, 96>;
26
+ //=> -78
27
+
28
+ type E = Subtract<PositiveInfinity, 9999>;
29
+ //=> Infinity
30
+
31
+ type F = Subtract<PositiveInfinity, PositiveInfinity>;
32
+ //=> number
33
+ ```
34
+
35
+ @category Numeric
36
+ */
37
+ // TODO: Support big integer.
38
+ export type Subtract<A extends number, B extends number> =
39
+ // Handle cases when A or B is the actual "number" type
40
+ number extends A | B ? number
41
+ // Handle cases when A and B are both +/- infinity
42
+ : A extends B & (PositiveInfinity | NegativeInfinity) ? number
43
+ // Handle cases when A is - infinity or B is + infinity
44
+ : A extends NegativeInfinity ? NegativeInfinity : B extends PositiveInfinity ? NegativeInfinity
45
+ // Handle cases when A is + infinity or B is - infinity
46
+ : A extends PositiveInfinity ? PositiveInfinity : B extends NegativeInfinity ? PositiveInfinity
47
+ // Handle case when numbers are equal to each other
48
+ : A extends B ? 0
49
+ // Handle cases when A or B is 0
50
+ : A extends 0 ? ReverseSign<B> : B extends 0 ? A
51
+ // Handle remaining regular cases
52
+ : SubtractPostChecks<A, B>;
53
+
54
+ /**
55
+ Subtracts two numbers A and B, such that they are not equal and neither of them are 0, +/- infinity or the `number` type
56
+ */
57
+ type SubtractPostChecks<A extends number, B extends number, AreNegative = [IsNegative<A>, IsNegative<B>]> =
58
+ AreNegative extends [false, false]
59
+ ? SubtractPositives<A, B>
60
+ : AreNegative extends [true, true]
61
+ // When both numbers are negative we subtract the absolute values and then reverse the sign
62
+ ? ReverseSign<SubtractPositives<NumberAbsolute<A>, NumberAbsolute<B>>>
63
+ // When the signs are different we can add the absolute values and then reverse the sign if A < B
64
+ : [...TupleOf<NumberAbsolute<A>>, ...TupleOf<NumberAbsolute<B>>] extends infer R extends unknown[]
65
+ ? LessThan<A, B> extends true ? ReverseSign<R['length']> : R['length']
66
+ : never;
67
+
68
+ /**
69
+ Subtracts two positive numbers.
70
+ */
71
+ type SubtractPositives<A extends number, B extends number> =
72
+ LessThan<A, B> extends true
73
+ // When A < B we can reverse the result of B - A
74
+ ? ReverseSign<SubtractIfAGreaterThanB<B, A>>
75
+ : SubtractIfAGreaterThanB<A, B>;
76
+
77
+ /**
78
+ Subtracts two positive numbers A and B such that A > B.
79
+ */
80
+ type SubtractIfAGreaterThanB<A extends number, B extends number> =
81
+ // This is where we always want to end up and do the actual subtraction
82
+ TupleOf<A> extends [...TupleOf<B>, ...infer R]
83
+ ? R['length']
84
+ : never;
85
+
86
+ export {};
@@ -0,0 +1,81 @@
1
+ import type {TupleOf} from './tuple-of.d.ts';
2
+ import type {NumberAbsolute, TupleMax, ReverseSign} from './internal/index.d.ts';
3
+ import type {PositiveInfinity, NegativeInfinity, IsNegative} from './numeric.d.ts';
4
+ import type {Subtract} from './subtract.d.ts';
5
+
6
+ /**
7
+ Returns the sum of two numbers.
8
+
9
+ Note:
10
+ - A or B can only support `-999` ~ `999`.
11
+
12
+ @example
13
+ ```
14
+ import type {Sum, PositiveInfinity, NegativeInfinity} from 'type-fest';
15
+
16
+ type A = Sum<111, 222>;
17
+ //=> 333
18
+
19
+ type B = Sum<-111, 222>;
20
+ //=> 111
21
+
22
+ type C = Sum<111, -222>;
23
+ //=> -111
24
+
25
+ type D = Sum<PositiveInfinity, -9999>;
26
+ //=> Infinity
27
+
28
+ type E = Sum<PositiveInfinity, NegativeInfinity>;
29
+ //=> number
30
+ ```
31
+
32
+ @category Numeric
33
+ */
34
+ // TODO: Support big integer.
35
+ export type Sum<A extends number, B extends number> =
36
+ // Handle cases when A or B is the actual "number" type
37
+ number extends A | B ? number
38
+ // Handle cases when A and B are both +/- infinity
39
+ : A extends B & (PositiveInfinity | NegativeInfinity) ? A // A or B could be used here as they are equal
40
+ // Handle cases when A and B are opposite infinities
41
+ : A | B extends PositiveInfinity | NegativeInfinity ? number
42
+ // Handle cases when A is +/- infinity
43
+ : A extends PositiveInfinity | NegativeInfinity ? A
44
+ // Handle cases when B is +/- infinity
45
+ : B extends PositiveInfinity | NegativeInfinity ? B
46
+ // Handle cases when A or B is 0 or it's the same number with different signs
47
+ : A extends 0 ? B : B extends 0 ? A : A extends ReverseSign<B> ? 0
48
+ // Handle remaining regular cases
49
+ : SumPostChecks<A, B>;
50
+
51
+ /**
52
+ 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
53
+ */
54
+ type SumPostChecks<A extends number, B extends number, AreNegative = [IsNegative<A>, IsNegative<B>]> =
55
+ AreNegative extends [false, false]
56
+ // When both numbers are positive we can add them together
57
+ ? SumPositives<A, B>
58
+ : AreNegative extends [true, true]
59
+ // When both numbers are negative we add the absolute values and then reverse the sign
60
+ ? ReverseSign<SumPositives<NumberAbsolute<A>, NumberAbsolute<B>>>
61
+ // When the signs are different we can subtract the absolute values, remove the sign
62
+ // and then reverse the sign if the larger absolute value is negative
63
+ : NumberAbsolute<Subtract<NumberAbsolute<A>, NumberAbsolute<B>>> extends infer Result extends number
64
+ ? TupleMax<[NumberAbsolute<A>, NumberAbsolute<B>]> extends infer Max_ extends number
65
+ ? Max_ extends A | B
66
+ // The larger absolute value is positive, so the result is positive
67
+ ? Result
68
+ // The larger absolute value is negative, so the result is negative
69
+ : ReverseSign<Result>
70
+ : never
71
+ : never;
72
+
73
+ /**
74
+ Adds two positive numbers.
75
+ */
76
+ type SumPositives<A extends number, B extends number> =
77
+ [...TupleOf<A>, ...TupleOf<B>]['length'] extends infer Result extends number
78
+ ? Result
79
+ : never;
80
+
81
+ export {};
@@ -0,0 +1,53 @@
1
+ /**
2
+ Create a union of types that share a common discriminant property.
3
+
4
+ Use-case: A shorter way to declare tagged unions with multiple members.
5
+
6
+ @example
7
+ ```
8
+ import type {TaggedUnion} from 'type-fest';
9
+
10
+ type Tagged<Fields extends Record<string, Record<string, unknown>>> = TaggedUnion<'type', Fields>;
11
+
12
+ // The TaggedUnion utility reduces the amount of boilerplate needed to create a tagged union with multiple members, making the code more concise.
13
+ type EventMessage = Tagged<{
14
+ OpenExternalUrl: {
15
+ url: string;
16
+ id: number;
17
+ language: string;
18
+ };
19
+ ToggleBackButtonVisibility: {
20
+ visible: boolean;
21
+ };
22
+ PurchaseButtonPressed: {
23
+ price: number;
24
+ time: Date;
25
+ };
26
+ NavigationStateChanged: {
27
+ navigation?: string;
28
+ };
29
+ }>;
30
+
31
+ // Here is the same type created without this utility.
32
+ type ManualEventMessage =
33
+ | {
34
+ type: 'OpenExternalUrl';
35
+ url: string;
36
+ id: number;
37
+ language: string;
38
+ }
39
+ | {type: 'ToggleBackButtonVisibility'; visible: boolean}
40
+ | {type: 'PurchaseButtonPressed'; price: number; time: Date}
41
+ | {type: 'NavigationStateChanged'; navigation?: string};
42
+ ```
43
+
44
+ @category Utilities
45
+ */
46
+ export type TaggedUnion<
47
+ TagKey extends string,
48
+ UnionMembers extends Record<string, Record<string, unknown>>,
49
+ > = {
50
+ [Name in keyof UnionMembers]: {[Key in TagKey]: Name} & UnionMembers[Name];
51
+ }[keyof UnionMembers];
52
+
53
+ export {};
@@ -0,0 +1,263 @@
1
+ import type tag from 'tagged-tag';
2
+
3
+ // eslint-disable-next-line type-fest/require-exported-types
4
+ export type TagContainer<Token> = {
5
+ readonly [tag]: Token;
6
+ };
7
+
8
+ type Tag<Token extends PropertyKey, TagMetadata> = TagContainer<{[K in Token]: TagMetadata}>;
9
+
10
+ /**
11
+ 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.)
12
+
13
+ A type returned by `Tagged` can be passed to `Tagged` again, to create a type with multiple tags.
14
+
15
+ [Read more about tagged types.](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d)
16
+
17
+ 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.
18
+
19
+ A type `A` returned by `Tagged` is assignable to another type `B` returned by `Tagged` if and only if:
20
+ - the underlying (untagged) type of `A` is assignable to the underlying type of `B`;
21
+ - `A` contains at least all the tags `B` has;
22
+ - and the metadata type for each of `A`'s tags is assignable to the metadata type of `B`'s corresponding tag.
23
+
24
+ There have been several discussions about adding similar features to TypeScript. Unfortunately, nothing has (yet) moved forward:
25
+ - [Microsoft/TypeScript#202](https://github.com/microsoft/TypeScript/issues/202)
26
+ - [Microsoft/TypeScript#4895](https://github.com/microsoft/TypeScript/issues/4895)
27
+ - [Microsoft/TypeScript#33290](https://github.com/microsoft/TypeScript/pull/33290)
28
+
29
+ @example
30
+ ```
31
+ import type {Tagged} from 'type-fest';
32
+
33
+ type AccountNumber = Tagged<number, 'AccountNumber'>;
34
+ type AccountBalance = Tagged<number, 'AccountBalance'>;
35
+
36
+ function createAccountNumber(): AccountNumber {
37
+ // As you can see, casting from a `number` (the underlying type being tagged) is allowed.
38
+ return 2 as AccountNumber;
39
+ }
40
+
41
+ declare function getMoneyForAccount(accountNumber: AccountNumber): AccountBalance;
42
+
43
+ // This will compile successfully.
44
+ getMoneyForAccount(createAccountNumber());
45
+
46
+ // But this won't, because it has to be explicitly passed as an `AccountNumber` type!
47
+ // Critically, you could not accidentally use an `AccountBalance` as an `AccountNumber`.
48
+ // @ts-expect-error
49
+ getMoneyForAccount(2);
50
+
51
+ // You can also use tagged values like their underlying, untagged type.
52
+ // I.e., this will compile successfully because an `AccountNumber` can be used as a regular `number`.
53
+ // In this sense, the underlying base type is not hidden, which differentiates tagged types from opaque types in other languages.
54
+ const accountNumber = createAccountNumber() + 2;
55
+ ```
56
+
57
+ @example
58
+ ```
59
+ import type {Tagged} from 'type-fest';
60
+
61
+ // You can apply multiple tags to a type by using `Tagged` repeatedly.
62
+ type Url = Tagged<string, 'URL'>;
63
+ type SpecialCacheKey = Tagged<Url, 'SpecialCacheKey'>;
64
+
65
+ // 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.
66
+ type SpecialCacheKey2 = Tagged<string, 'URL' | 'SpecialCacheKey'>;
67
+ ```
68
+
69
+ @category Type
70
+ */
71
+ export type Tagged<Type, TagName extends PropertyKey, TagMetadata = never> = Type & Tag<TagName, TagMetadata>;
72
+
73
+ /**
74
+ Given a type and a tag name, returns the metadata associated with that tag on that type.
75
+
76
+ 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.
77
+
78
+ 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).
79
+
80
+ @example
81
+ ```
82
+ import type {Tagged, GetTagMetadata} from 'type-fest';
83
+
84
+ type JsonOf<T> = Tagged<string, 'JSON', T>;
85
+
86
+ function stringify<T>(it: T) {
87
+ return JSON.stringify(it) as JsonOf<T>;
88
+ }
89
+
90
+ function parse<T extends JsonOf<unknown>>(it: T) {
91
+ return JSON.parse(it) as GetTagMetadata<T, 'JSON'>;
92
+ }
93
+
94
+ const x = stringify({hello: 'world'});
95
+ const parsed = parse(x); // The type of `parsed` is { hello: string }
96
+ ```
97
+
98
+ @category Type
99
+ */
100
+ export type GetTagMetadata<Type extends Tag<TagName, unknown>, TagName extends PropertyKey> = Type[typeof tag][TagName];
101
+
102
+ /**
103
+ Revert a tagged type back to its original type by removing all tags.
104
+
105
+ Why is this necessary?
106
+
107
+ 1. Use a `Tagged` type as object keys
108
+ 2. Prevent TS4058 error: "Return type of exported function has or is using name X from external module Y but cannot be named"
109
+
110
+ @example
111
+ ```
112
+ import type {Tagged, UnwrapTagged} from 'type-fest';
113
+
114
+ type AccountType = Tagged<'SAVINGS' | 'CHECKING', 'AccountType'>;
115
+
116
+ const moneyByAccountType: Record<UnwrapTagged<AccountType>, number> = {
117
+ SAVINGS: 99,
118
+ CHECKING: 0.1,
119
+ };
120
+
121
+ // Without UnwrapTagged, the following expression would throw a type error.
122
+ const money = moneyByAccountType.SAVINGS; // TS error: Property 'SAVINGS' does not exist
123
+
124
+ // Attempting to pass an non-Tagged type to UnwrapTagged will raise a type error.
125
+ // @ts-expect-error
126
+ type WontWork = UnwrapTagged<string>;
127
+ ```
128
+
129
+ @category Type
130
+ */
131
+ export type UnwrapTagged<TaggedType extends Tag<PropertyKey, any>> =
132
+ RemoveAllTags<TaggedType>;
133
+
134
+ type RemoveAllTags<T> = T extends Tag<PropertyKey, any>
135
+ ? {
136
+ [ThisTag in keyof T[typeof tag]]: T extends Tagged<infer Type, ThisTag, T[typeof tag][ThisTag]>
137
+ ? RemoveAllTags<Type>
138
+ : never
139
+ }[keyof T[typeof tag]]
140
+ : T;
141
+
142
+ /**
143
+ Note: The `Opaque` type is deprecated in favor of `Tagged`.
144
+
145
+ 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.)
146
+
147
+ The generic type parameters can be anything.
148
+
149
+ Note that `Opaque` is somewhat of a misnomer here, in that, unlike [some alternative implementations](https://github.com/microsoft/TypeScript/issues/4895#issuecomment-425132582), the original, untagged type is not actually hidden. (E.g., functions that accept the untagged type can still be called with the "opaque" version -- but not vice-versa.)
150
+
151
+ Also note that this implementation is limited to a single tag. If you want to allow multiple tags, use `Tagged` instead.
152
+
153
+ [Read more about tagged types.](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d)
154
+
155
+ There have been several discussions about adding similar features to TypeScript. Unfortunately, nothing has (yet) moved forward:
156
+ - [Microsoft/TypeScript#202](https://github.com/microsoft/TypeScript/issues/202)
157
+ - [Microsoft/TypeScript#15408](https://github.com/Microsoft/TypeScript/issues/15408)
158
+ - [Microsoft/TypeScript#15807](https://github.com/Microsoft/TypeScript/issues/15807)
159
+
160
+ @example
161
+ ```
162
+ import type {Opaque} from 'type-fest';
163
+
164
+ type AccountNumber = Opaque<number, 'AccountNumber'>;
165
+ type AccountBalance = Opaque<number, 'AccountBalance'>;
166
+
167
+ // The `Token` parameter allows the compiler to differentiate between types, whereas "unknown" will not. For example, consider the following structures:
168
+ type ThingOne = Opaque<string>;
169
+ type ThingTwo = Opaque<string>;
170
+
171
+ // To the compiler, these types are allowed to be cast to each other as they have the same underlying type. They are both `string & { __opaque__: unknown }`.
172
+ // To avoid this behaviour, you would instead pass the "Token" parameter, like so.
173
+ type NewThingOne = Opaque<string, 'ThingOne'>;
174
+ type NewThingTwo = Opaque<string, 'ThingTwo'>;
175
+
176
+ // Now they're completely separate types, so the following will fail to compile.
177
+ function createNewThingOne(): NewThingOne {
178
+ // As you can see, casting from a string is still allowed. However, you may not cast NewThingOne to NewThingTwo, and vice versa.
179
+ return 'new thing one' as NewThingOne;
180
+ }
181
+
182
+ // This will fail to compile, as they are fundamentally different types.
183
+ // @ts-expect-error
184
+ const thingTwo = createNewThingOne() as NewThingTwo;
185
+
186
+ // Here's another example of opaque typing.
187
+ function createAccountNumber(): AccountNumber {
188
+ return 2 as AccountNumber;
189
+ }
190
+
191
+ declare function getMoneyForAccount(accountNumber: AccountNumber): AccountBalance;
192
+
193
+ // This will compile successfully.
194
+ getMoneyForAccount(createAccountNumber());
195
+
196
+ // But this won't, because it has to be explicitly passed as an `AccountNumber` type.
197
+ // @ts-expect-error
198
+ getMoneyForAccount(2);
199
+
200
+ // You can use opaque values like they aren't opaque too.
201
+ const accountNumber = createAccountNumber();
202
+
203
+ // This will compile successfully.
204
+ const newAccountNumber = accountNumber + 2;
205
+
206
+ // As a side note, you can (and should) use recursive types for your opaque types to make them stronger and hopefully easier to type.
207
+ type Person = {
208
+ id: Opaque<number, Person>;
209
+ name: string;
210
+ };
211
+ ```
212
+
213
+ @category Type
214
+ @deprecated Use {@link Tagged} instead
215
+ */
216
+ export type Opaque<Type, Token = unknown> = Type & TagContainer<Token>;
217
+
218
+ /**
219
+ Note: The `UnwrapOpaque` type is deprecated in favor of `UnwrapTagged`.
220
+
221
+ Revert an opaque or tagged type back to its original type by removing the readonly `[tag]`.
222
+
223
+ Why is this necessary?
224
+
225
+ 1. Use an `Opaque` type as object keys
226
+ 2. Prevent TS4058 error: "Return type of exported function has or is using name X from external module Y but cannot be named"
227
+
228
+ @example
229
+ ```
230
+ import type {Opaque, UnwrapOpaque} from 'type-fest';
231
+
232
+ type AccountType = Opaque<'SAVINGS' | 'CHECKING', 'AccountType'>;
233
+
234
+ const moneyByAccountType: Record<UnwrapOpaque<AccountType>, number> = {
235
+ SAVINGS: 99,
236
+ CHECKING: 0.1,
237
+ };
238
+
239
+ // Without UnwrapOpaque, the following expression would throw a type error.
240
+ const money = moneyByAccountType.SAVINGS; // TS error: Property 'SAVINGS' does not exist
241
+
242
+ // Attempting to pass an non-Opaque type to UnwrapOpaque will raise a type error.
243
+ // @ts-expect-error
244
+ type WontWork = UnwrapOpaque<string>;
245
+
246
+ // Using a Tagged type will work too.
247
+ // @ts-expect-error
248
+ type WillWork = UnwrapOpaque<Tagged<number, 'AccountNumber'>>; // number
249
+ ```
250
+
251
+ @category Type
252
+ @deprecated Use {@link UnwrapTagged} instead
253
+ */
254
+ export type UnwrapOpaque<OpaqueType extends TagContainer<unknown>> =
255
+ OpaqueType extends Tag<PropertyKey, any>
256
+ ? RemoveAllTags<OpaqueType>
257
+ : OpaqueType extends Opaque<infer Type, OpaqueType[typeof tag]>
258
+ ? Type
259
+ : OpaqueType;
260
+
261
+ export {type default as tag} from 'tagged-tag';
262
+
263
+ export {};
@@ -0,0 +1,29 @@
1
+ import type {Whitespace} from './internal/index.d.ts';
2
+
3
+ /**
4
+ Remove spaces from the left side.
5
+ */
6
+ type TrimLeft<V extends string> = V extends `${Whitespace}${infer R}` ? TrimLeft<R> : V;
7
+
8
+ /**
9
+ Remove spaces from the right side.
10
+ */
11
+ type TrimRight<V extends string> = V extends `${infer R}${Whitespace}` ? TrimRight<R> : V;
12
+
13
+ /**
14
+ Remove leading and trailing spaces from a string.
15
+
16
+ @example
17
+ ```
18
+ import type {Trim} from 'type-fest';
19
+
20
+ type Example = Trim<' foo '>;
21
+ //=> 'foo'
22
+ ```
23
+
24
+ @category String
25
+ @category Template literal
26
+ */
27
+ export type Trim<V extends string> = TrimLeft<TrimRight<V>>;
28
+
29
+ export {};