effect 2.3.8 → 2.4.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 (272) hide show
  1. package/dist/cjs/BigInt.js +14 -1
  2. package/dist/cjs/BigInt.js.map +1 -1
  3. package/dist/cjs/Effect.js +16 -61
  4. package/dist/cjs/Effect.js.map +1 -1
  5. package/dist/cjs/Either.js +35 -6
  6. package/dist/cjs/Either.js.map +1 -1
  7. package/dist/cjs/Equal.js +1 -1
  8. package/dist/cjs/Equal.js.map +1 -1
  9. package/dist/cjs/Exit.js +1 -1
  10. package/dist/cjs/Number.js +25 -1
  11. package/dist/cjs/Number.js.map +1 -1
  12. package/dist/cjs/ReadonlyArray.js +2 -2
  13. package/dist/cjs/ReadonlyArray.js.map +1 -1
  14. package/dist/cjs/ReadonlyRecord.js +71 -76
  15. package/dist/cjs/ReadonlyRecord.js.map +1 -1
  16. package/dist/cjs/STM.js.map +1 -1
  17. package/dist/cjs/Schedule.js.map +1 -1
  18. package/dist/cjs/Sink.js.map +1 -1
  19. package/dist/cjs/Stream.js +3 -23
  20. package/dist/cjs/Stream.js.map +1 -1
  21. package/dist/cjs/Struct.js +3 -1
  22. package/dist/cjs/Struct.js.map +1 -1
  23. package/dist/cjs/TestAnnotation.js.map +1 -1
  24. package/dist/cjs/internal/channel/channelExecutor.js +5 -5
  25. package/dist/cjs/internal/channel/channelExecutor.js.map +1 -1
  26. package/dist/cjs/internal/channel/channelState.js +5 -5
  27. package/dist/cjs/internal/channel/channelState.js.map +1 -1
  28. package/dist/cjs/internal/channel.js.map +1 -1
  29. package/dist/cjs/internal/clock.js +3 -4
  30. package/dist/cjs/internal/clock.js.map +1 -1
  31. package/dist/cjs/internal/core-effect.js +6 -23
  32. package/dist/cjs/internal/core-effect.js.map +1 -1
  33. package/dist/cjs/internal/core.js +11 -27
  34. package/dist/cjs/internal/core.js.map +1 -1
  35. package/dist/cjs/internal/effect/circular.js +4 -5
  36. package/dist/cjs/internal/effect/circular.js.map +1 -1
  37. package/dist/cjs/internal/either.js +3 -3
  38. package/dist/cjs/internal/either.js.map +1 -1
  39. package/dist/cjs/internal/groupBy.js.map +1 -1
  40. package/dist/cjs/internal/layer.js +0 -2
  41. package/dist/cjs/internal/layer.js.map +1 -1
  42. package/dist/cjs/internal/runtime.js +12 -1
  43. package/dist/cjs/internal/runtime.js.map +1 -1
  44. package/dist/cjs/internal/schedule.js +4 -4
  45. package/dist/cjs/internal/schedule.js.map +1 -1
  46. package/dist/cjs/internal/sink.js +0 -2
  47. package/dist/cjs/internal/sink.js.map +1 -1
  48. package/dist/cjs/internal/stm/stm.js +1 -0
  49. package/dist/cjs/internal/stm/stm.js.map +1 -1
  50. package/dist/cjs/internal/stream.js +51 -64
  51. package/dist/cjs/internal/stream.js.map +1 -1
  52. package/dist/cjs/internal/version.js +1 -1
  53. package/dist/dts/BigInt.d.ts +7 -0
  54. package/dist/dts/BigInt.d.ts.map +1 -1
  55. package/dist/dts/Brand.d.ts +1 -1
  56. package/dist/dts/Brand.d.ts.map +1 -1
  57. package/dist/dts/Cause.d.ts +1 -1
  58. package/dist/dts/Cause.d.ts.map +1 -1
  59. package/dist/dts/Channel.d.ts +11 -11
  60. package/dist/dts/Channel.d.ts.map +1 -1
  61. package/dist/dts/Chunk.d.ts +3 -3
  62. package/dist/dts/Config.d.ts +4 -4
  63. package/dist/dts/Config.d.ts.map +1 -1
  64. package/dist/dts/Cron.d.ts +1 -1
  65. package/dist/dts/Cron.d.ts.map +1 -1
  66. package/dist/dts/Differ.d.ts +2 -2
  67. package/dist/dts/Differ.d.ts.map +1 -1
  68. package/dist/dts/Effect.d.ts +52 -108
  69. package/dist/dts/Effect.d.ts.map +1 -1
  70. package/dist/dts/Either.d.ts +126 -83
  71. package/dist/dts/Either.d.ts.map +1 -1
  72. package/dist/dts/Encoding.d.ts +6 -6
  73. package/dist/dts/Encoding.d.ts.map +1 -1
  74. package/dist/dts/Equal.d.ts.map +1 -1
  75. package/dist/dts/Exit.d.ts +2 -2
  76. package/dist/dts/Fiber.d.ts +2 -2
  77. package/dist/dts/Fiber.d.ts.map +1 -1
  78. package/dist/dts/GroupBy.d.ts +12 -12
  79. package/dist/dts/GroupBy.d.ts.map +1 -1
  80. package/dist/dts/Layer.d.ts +26 -26
  81. package/dist/dts/Layer.d.ts.map +1 -1
  82. package/dist/dts/List.d.ts +2 -2
  83. package/dist/dts/Logger.d.ts +4 -4
  84. package/dist/dts/Match.d.ts +2 -2
  85. package/dist/dts/Match.d.ts.map +1 -1
  86. package/dist/dts/MergeDecision.d.ts +1 -1
  87. package/dist/dts/MergeState.d.ts +5 -5
  88. package/dist/dts/MergeState.d.ts.map +1 -1
  89. package/dist/dts/Metric.d.ts +13 -13
  90. package/dist/dts/Metric.d.ts.map +1 -1
  91. package/dist/dts/MetricPolling.d.ts +4 -4
  92. package/dist/dts/MetricPolling.d.ts.map +1 -1
  93. package/dist/dts/Number.d.ts +8 -0
  94. package/dist/dts/Number.d.ts.map +1 -1
  95. package/dist/dts/Option.d.ts +11 -11
  96. package/dist/dts/ReadonlyArray.d.ts +9 -8
  97. package/dist/dts/ReadonlyArray.d.ts.map +1 -1
  98. package/dist/dts/ReadonlyRecord.d.ts +111 -94
  99. package/dist/dts/ReadonlyRecord.d.ts.map +1 -1
  100. package/dist/dts/Reloadable.d.ts +4 -4
  101. package/dist/dts/Reloadable.d.ts.map +1 -1
  102. package/dist/dts/RequestResolver.d.ts +13 -13
  103. package/dist/dts/RequestResolver.d.ts.map +1 -1
  104. package/dist/dts/Resource.d.ts +1 -1
  105. package/dist/dts/Resource.d.ts.map +1 -1
  106. package/dist/dts/STM.d.ts +144 -139
  107. package/dist/dts/STM.d.ts.map +1 -1
  108. package/dist/dts/Schedule.d.ts +171 -179
  109. package/dist/dts/Schedule.d.ts.map +1 -1
  110. package/dist/dts/SingleProducerAsyncInput.d.ts +1 -1
  111. package/dist/dts/SingleProducerAsyncInput.d.ts.map +1 -1
  112. package/dist/dts/Sink.d.ts +13 -13
  113. package/dist/dts/Sink.d.ts.map +1 -1
  114. package/dist/dts/Stream.d.ts +355 -366
  115. package/dist/dts/Stream.d.ts.map +1 -1
  116. package/dist/dts/Struct.d.ts +3 -3
  117. package/dist/dts/Struct.d.ts.map +1 -1
  118. package/dist/dts/SubscriptionRef.d.ts +2 -2
  119. package/dist/dts/TArray.d.ts +2 -2
  120. package/dist/dts/TDeferred.d.ts +3 -3
  121. package/dist/dts/TMap.d.ts +10 -10
  122. package/dist/dts/TSet.d.ts +4 -4
  123. package/dist/dts/Take.d.ts +2 -2
  124. package/dist/dts/TestAnnotation.d.ts +2 -2
  125. package/dist/dts/TestAnnotation.d.ts.map +1 -1
  126. package/dist/dts/Types.d.ts +7 -0
  127. package/dist/dts/Types.d.ts.map +1 -1
  128. package/dist/dts/internal/stm/stm.d.ts +2 -15
  129. package/dist/dts/internal/stm/stm.d.ts.map +1 -1
  130. package/dist/esm/BigInt.js +12 -0
  131. package/dist/esm/BigInt.js.map +1 -1
  132. package/dist/esm/Effect.js +13 -58
  133. package/dist/esm/Effect.js.map +1 -1
  134. package/dist/esm/Either.js +42 -5
  135. package/dist/esm/Either.js.map +1 -1
  136. package/dist/esm/Equal.js +1 -1
  137. package/dist/esm/Equal.js.map +1 -1
  138. package/dist/esm/Exit.js +1 -1
  139. package/dist/esm/Number.js +23 -0
  140. package/dist/esm/Number.js.map +1 -1
  141. package/dist/esm/ReadonlyArray.js +2 -2
  142. package/dist/esm/ReadonlyArray.js.map +1 -1
  143. package/dist/esm/ReadonlyRecord.js +70 -75
  144. package/dist/esm/ReadonlyRecord.js.map +1 -1
  145. package/dist/esm/STM.js.map +1 -1
  146. package/dist/esm/Schedule.js.map +1 -1
  147. package/dist/esm/Sink.js.map +1 -1
  148. package/dist/esm/Stream.js +5 -22
  149. package/dist/esm/Stream.js.map +1 -1
  150. package/dist/esm/Struct.js +3 -1
  151. package/dist/esm/Struct.js.map +1 -1
  152. package/dist/esm/TestAnnotation.js.map +1 -1
  153. package/dist/esm/internal/channel/channelExecutor.js +5 -5
  154. package/dist/esm/internal/channel/channelExecutor.js.map +1 -1
  155. package/dist/esm/internal/channel/channelState.js +3 -3
  156. package/dist/esm/internal/channel/channelState.js.map +1 -1
  157. package/dist/esm/internal/channel.js.map +1 -1
  158. package/dist/esm/internal/clock.js +3 -4
  159. package/dist/esm/internal/clock.js.map +1 -1
  160. package/dist/esm/internal/core-effect.js +4 -20
  161. package/dist/esm/internal/core-effect.js.map +1 -1
  162. package/dist/esm/internal/core.js +8 -22
  163. package/dist/esm/internal/core.js.map +1 -1
  164. package/dist/esm/internal/effect/circular.js +4 -5
  165. package/dist/esm/internal/effect/circular.js.map +1 -1
  166. package/dist/esm/internal/either.js +3 -3
  167. package/dist/esm/internal/either.js.map +1 -1
  168. package/dist/esm/internal/groupBy.js.map +1 -1
  169. package/dist/esm/internal/layer.js +0 -2
  170. package/dist/esm/internal/layer.js.map +1 -1
  171. package/dist/esm/internal/runtime.js +12 -1
  172. package/dist/esm/internal/runtime.js.map +1 -1
  173. package/dist/esm/internal/schedule.js +4 -4
  174. package/dist/esm/internal/schedule.js.map +1 -1
  175. package/dist/esm/internal/sink.js +0 -2
  176. package/dist/esm/internal/sink.js.map +1 -1
  177. package/dist/esm/internal/stm/stm.js +1 -0
  178. package/dist/esm/internal/stm/stm.js.map +1 -1
  179. package/dist/esm/internal/stream.js +49 -59
  180. package/dist/esm/internal/stream.js.map +1 -1
  181. package/dist/esm/internal/version.js +1 -1
  182. package/package.json +1 -1
  183. package/src/BigInt.ts +13 -0
  184. package/src/Brand.ts +4 -4
  185. package/src/Cause.ts +1 -1
  186. package/src/Channel.ts +17 -17
  187. package/src/Chunk.ts +4 -4
  188. package/src/Config.ts +4 -4
  189. package/src/Cron.ts +2 -2
  190. package/src/Differ.ts +2 -2
  191. package/src/Effect.ts +68 -145
  192. package/src/Either.ts +215 -133
  193. package/src/Encoding.ts +3 -3
  194. package/src/Equal.ts +1 -1
  195. package/src/Exit.ts +2 -2
  196. package/src/Fiber.ts +2 -2
  197. package/src/GroupBy.ts +16 -16
  198. package/src/Layer.ts +32 -32
  199. package/src/List.ts +3 -3
  200. package/src/Logger.ts +4 -4
  201. package/src/Match.ts +3 -3
  202. package/src/MergeDecision.ts +1 -1
  203. package/src/MergeState.ts +8 -8
  204. package/src/Metric.ts +13 -13
  205. package/src/MetricPolling.ts +9 -9
  206. package/src/Number.ts +26 -0
  207. package/src/Option.ts +17 -17
  208. package/src/ReadonlyArray.ts +23 -15
  209. package/src/ReadonlyRecord.ts +421 -265
  210. package/src/Reloadable.ts +4 -4
  211. package/src/RequestResolver.ts +19 -19
  212. package/src/Resource.ts +3 -3
  213. package/src/STM.ts +166 -213
  214. package/src/Schedule.ts +331 -361
  215. package/src/SingleProducerAsyncInput.ts +1 -1
  216. package/src/Sink.ts +19 -19
  217. package/src/Stream.ts +449 -456
  218. package/src/Struct.ts +8 -5
  219. package/src/SubscriptionRef.ts +2 -2
  220. package/src/TArray.ts +2 -2
  221. package/src/TDeferred.ts +4 -4
  222. package/src/TMap.ts +10 -10
  223. package/src/TSet.ts +4 -4
  224. package/src/Take.ts +4 -4
  225. package/src/TestAnnotation.ts +5 -8
  226. package/src/Types.ts +11 -0
  227. package/src/internal/blockedRequests.ts +2 -2
  228. package/src/internal/cause.ts +2 -2
  229. package/src/internal/channel/channelExecutor.ts +26 -26
  230. package/src/internal/channel/channelState.ts +13 -13
  231. package/src/internal/channel/mergeDecision.ts +1 -1
  232. package/src/internal/channel/mergeState.ts +6 -6
  233. package/src/internal/channel/singleProducerAsyncInput.ts +5 -5
  234. package/src/internal/channel.ts +43 -43
  235. package/src/internal/clock.ts +3 -4
  236. package/src/internal/config.ts +7 -7
  237. package/src/internal/configError.ts +1 -1
  238. package/src/internal/configProvider/pathPatch.ts +2 -2
  239. package/src/internal/configProvider.ts +1 -1
  240. package/src/internal/core-effect.ts +28 -43
  241. package/src/internal/core.ts +15 -40
  242. package/src/internal/dataSource.ts +26 -26
  243. package/src/internal/differ/orPatch.ts +7 -7
  244. package/src/internal/differ.ts +2 -2
  245. package/src/internal/effect/circular.ts +9 -10
  246. package/src/internal/either.ts +25 -22
  247. package/src/internal/encoding/base64.ts +1 -1
  248. package/src/internal/encoding/base64Url.ts +1 -1
  249. package/src/internal/encoding/hex.ts +1 -1
  250. package/src/internal/fiber.ts +2 -2
  251. package/src/internal/fiberRuntime.ts +9 -9
  252. package/src/internal/groupBy.ts +40 -40
  253. package/src/internal/layer/circular.ts +4 -4
  254. package/src/internal/layer.ts +52 -54
  255. package/src/internal/matcher.ts +5 -5
  256. package/src/internal/metric/polling.ts +8 -8
  257. package/src/internal/metric.ts +6 -6
  258. package/src/internal/reloadable.ts +4 -4
  259. package/src/internal/resource.ts +2 -2
  260. package/src/internal/runtime.ts +32 -19
  261. package/src/internal/schedule.ts +430 -500
  262. package/src/internal/sink.ts +27 -29
  263. package/src/internal/stm/core.ts +23 -23
  264. package/src/internal/stm/stm.ts +158 -157
  265. package/src/internal/stm/tArray.ts +3 -3
  266. package/src/internal/stm/tDeferred.ts +5 -5
  267. package/src/internal/stm/tMap.ts +13 -13
  268. package/src/internal/stm/tSet.ts +4 -4
  269. package/src/internal/stream.ts +688 -723
  270. package/src/internal/subscriptionRef.ts +3 -3
  271. package/src/internal/take.ts +6 -6
  272. package/src/internal/version.ts +1 -1
@@ -17,16 +17,39 @@ import type { NoInfer } from "./Types.js"
17
17
  * @category models
18
18
  * @since 2.0.0
19
19
  */
20
- export interface ReadonlyRecord<out A> {
21
- readonly [x: string]: A
20
+ export type ReadonlyRecord<in out K extends string | symbol, out A> = {
21
+ readonly [P in K]: A
22
+ }
23
+
24
+ /**
25
+ * @since 2.0.0
26
+ */
27
+ export declare namespace ReadonlyRecord {
28
+ type IsFiniteString<T extends string> = T extends "" ? true :
29
+ [T] extends [`${infer Head}${infer Rest}`]
30
+ ? string extends Head ? false : `${number}` extends Head ? false : Rest extends "" ? true : IsFiniteString<Rest>
31
+ : false
32
+
33
+ /**
34
+ * @since 2.0.0
35
+ */
36
+ export type NonLiteralKey<K extends string | symbol> = K extends string ? IsFiniteString<K> extends true ? string : K
37
+ : symbol
38
+
39
+ /**
40
+ * @since 2.0.0
41
+ */
42
+ export type IntersectKeys<K1 extends string, K2 extends string> = [string] extends [K1 | K2] ?
43
+ NonLiteralKey<K1> & NonLiteralKey<K2>
44
+ : K1 & K2
22
45
  }
23
46
 
24
47
  /**
25
48
  * @category type lambdas
26
49
  * @since 2.0.0
27
50
  */
28
- export interface ReadonlyRecordTypeLambda extends TypeLambda {
29
- readonly type: ReadonlyRecord<this["Target"]>
51
+ export interface ReadonlyRecordTypeLambda<K extends string = string> extends TypeLambda {
52
+ readonly type: ReadonlyRecord<K, this["Target"]>
30
53
  }
31
54
 
32
55
  /**
@@ -35,7 +58,10 @@ export interface ReadonlyRecordTypeLambda extends TypeLambda {
35
58
  * @category constructors
36
59
  * @since 2.0.0
37
60
  */
38
- export const empty = <A>(): Record<string, A> => ({})
61
+ export const empty = <K extends string | symbol = never, V = never>(): Record<
62
+ ReadonlyRecord.NonLiteralKey<K>,
63
+ V
64
+ > => ({} as any)
39
65
 
40
66
  /**
41
67
  * Determine if a record is empty.
@@ -51,14 +77,8 @@ export const empty = <A>(): Record<string, A> => ({})
51
77
  * @category guards
52
78
  * @since 2.0.0
53
79
  */
54
- export const isEmptyRecord = <A>(self: Record<string, A>): self is Record<string, never> => {
55
- for (const k in self) {
56
- if (has(self, k)) {
57
- return false
58
- }
59
- }
60
- return true
61
- }
80
+ export const isEmptyRecord = <K extends string, A>(self: Record<K, A>): self is Record<K, never> =>
81
+ keys(self).length === 0
62
82
 
63
83
  /**
64
84
  * Determine if a record is empty.
@@ -74,7 +94,9 @@ export const isEmptyRecord = <A>(self: Record<string, A>): self is Record<string
74
94
  * @category guards
75
95
  * @since 2.0.0
76
96
  */
77
- export const isEmptyReadonlyRecord: <A>(self: ReadonlyRecord<A>) => self is ReadonlyRecord<never> = isEmptyRecord
97
+ export const isEmptyReadonlyRecord: <K extends string, A>(
98
+ self: ReadonlyRecord<K, A>
99
+ ) => self is ReadonlyRecord<K, never> = isEmptyRecord
78
100
 
79
101
  /**
80
102
  * Takes an iterable and a projection function and returns a record.
@@ -97,25 +119,26 @@ export const isEmptyReadonlyRecord: <A>(self: ReadonlyRecord<A>) => self is Read
97
119
  * @since 2.0.0
98
120
  */
99
121
  export const fromIterableWith: {
100
- <A, B>(f: (a: A) => readonly [string, B]): (self: Iterable<A>) => Record<string, B>
101
- <A, B>(self: Iterable<A>, f: (a: A) => readonly [string, B]): Record<string, B>
102
- } = dual(2, <A, B>(self: Iterable<A>, f: (a: A) => readonly [string, B]): Record<string, B> => {
103
- const out: Record<string, B> = {}
104
- for (const a of self) {
105
- const [k, b] = f(a)
106
- out[k] = b
122
+ <A, K extends string | symbol, B>(
123
+ f: (a: A) => readonly [K, B]
124
+ ): (self: Iterable<A>) => Record<ReadonlyRecord.NonLiteralKey<K>, B>
125
+ <A, K extends string | symbol, B>(
126
+ self: Iterable<A>,
127
+ f: (a: A) => readonly [K, B]
128
+ ): Record<ReadonlyRecord.NonLiteralKey<K>, B>
129
+ } = dual(
130
+ 2,
131
+ <A, K extends string, B>(
132
+ self: Iterable<A>,
133
+ f: (a: A) => readonly [K, B]
134
+ ): Record<ReadonlyRecord.NonLiteralKey<K>, B> => {
135
+ const out: Record<string, B> = empty()
136
+ for (const a of self) {
137
+ const [k, b] = f(a)
138
+ out[k] = b
139
+ }
140
+ return out
107
141
  }
108
- return out
109
- })
110
-
111
- /**
112
- * Creates a new record from an iterable collection of key/value pairs.
113
- *
114
- * @since 2.0.0
115
- * @category constructors
116
- */
117
- export const fromIterable: <V>(entries: Iterable<readonly [string, V]>) => Record<string, V> = fromIterableWith(
118
- identity
119
142
  )
120
143
 
121
144
  /**
@@ -143,8 +166,10 @@ export const fromIterable: <V>(entries: Iterable<readonly [string, V]>) => Recor
143
166
  * @category constructors
144
167
  * @since 2.0.0
145
168
  */
146
- export const fromIterableBy = <A>(items: Iterable<A>, f: (a: A) => string): Record<string, A> =>
147
- fromIterableWith(items, (a) => [f(a), a])
169
+ export const fromIterableBy = <A, K extends string | symbol>(
170
+ items: Iterable<A>,
171
+ f: (a: A) => K
172
+ ): Record<ReadonlyRecord.NonLiteralKey<K>, A> => fromIterableWith(items, (a) => [f(a), a])
148
173
 
149
174
  /**
150
175
  * Builds a record from an iterable of key-value pairs.
@@ -161,10 +186,12 @@ export const fromIterableBy = <A>(items: Iterable<A>, f: (a: A) => string): Reco
161
186
  *
162
187
  * assert.deepStrictEqual(fromEntries(input), { a: 1, b: 2 })
163
188
  *
164
- * @category conversions
165
189
  * @since 2.0.0
190
+ * @category constructors
166
191
  */
167
- export const fromEntries: <A>(self: Iterable<readonly [string, A]>) => Record<string, A> = fromIterableWith(identity)
192
+ export const fromEntries: <Entry extends readonly [string | symbol, any]>(
193
+ entries: Iterable<Entry>
194
+ ) => Record<ReadonlyRecord.NonLiteralKey<Entry[0]>, Entry[1]> = Object.fromEntries
168
195
 
169
196
  /**
170
197
  * Transforms the values of a record into an `Array` with a custom mapping function.
@@ -182,13 +209,13 @@ export const fromEntries: <A>(self: Iterable<readonly [string, A]>) => Record<st
182
209
  * @since 2.0.0
183
210
  */
184
211
  export const collect: {
185
- <K extends string, A, B>(f: (key: K, a: A) => B): (self: Record<K, A>) => Array<B>
186
- <K extends string, A, B>(self: Record<K, A>, f: (key: K, a: A) => B): Array<B>
212
+ <K extends string, A, B>(f: (key: K, a: A) => B): (self: ReadonlyRecord<K, A>) => Array<B>
213
+ <K extends string, A, B>(self: ReadonlyRecord<K, A>, f: (key: K, a: A) => B): Array<B>
187
214
  } = dual(
188
215
  2,
189
- <A, B>(self: ReadonlyRecord<A>, f: (key: string, a: A) => B): Array<B> => {
216
+ <K extends string, A, B>(self: ReadonlyRecord<K, A>, f: (key: K, a: A) => B): Array<B> => {
190
217
  const out: Array<B> = []
191
- for (const key of Object.keys(self)) {
218
+ for (const key of keys(self)) {
192
219
  out.push(f(key, self[key]))
193
220
  }
194
221
  return out
@@ -209,7 +236,7 @@ export const collect: {
209
236
  * @category conversions
210
237
  * @since 2.0.0
211
238
  */
212
- export const toEntries: <K extends string, A>(self: Record<K, A>) => Array<[K, A]> = collect((
239
+ export const toEntries: <K extends string, A>(self: ReadonlyRecord<K, A>) => Array<[K, A]> = collect((
213
240
  key,
214
241
  value
215
242
  ) => [key, value])
@@ -226,7 +253,7 @@ export const toEntries: <K extends string, A>(self: Record<K, A>) => Array<[K, A
226
253
  *
227
254
  * @since 2.0.0
228
255
  */
229
- export const size = <A>(self: ReadonlyRecord<A>): number => Object.keys(self).length
256
+ export const size = <K extends string, A>(self: ReadonlyRecord<K, A>): number => keys(self).length
230
257
 
231
258
  /**
232
259
  * Check if a given `key` exists in a record.
@@ -235,19 +262,27 @@ export const size = <A>(self: ReadonlyRecord<A>): number => Object.keys(self).le
235
262
  * @param key - the key to look for in the record.
236
263
  *
237
264
  * @example
238
- * import { has } from "effect/ReadonlyRecord"
265
+ * import { empty, has } from "effect/ReadonlyRecord"
239
266
  *
240
267
  * assert.deepStrictEqual(has({ a: 1, b: 2 }, "a"), true);
241
- * assert.deepStrictEqual(has({ a: 1, b: 2 }, "c"), false);
268
+ * assert.deepStrictEqual(has(empty<string>(), "c"), false);
242
269
  *
243
270
  * @since 2.0.0
244
271
  */
245
272
  export const has: {
246
- (key: string): <A>(self: ReadonlyRecord<A>) => boolean
247
- <A>(self: ReadonlyRecord<A>, key: string): boolean
273
+ <K extends string | symbol>(
274
+ key: NoInfer<K>
275
+ ): <A>(self: ReadonlyRecord<K, A>) => boolean
276
+ <K extends string | symbol, A>(
277
+ self: ReadonlyRecord<K, A>,
278
+ key: NoInfer<K>
279
+ ): boolean
248
280
  } = dual(
249
281
  2,
250
- <A>(self: ReadonlyRecord<A>, key: string): boolean => Object.prototype.hasOwnProperty.call(self, key)
282
+ <K extends string | symbol, A>(
283
+ self: ReadonlyRecord<K, A>,
284
+ key: NoInfer<K>
285
+ ): boolean => Object.prototype.hasOwnProperty.call(self, key)
251
286
  )
252
287
 
253
288
  /**
@@ -260,7 +295,7 @@ export const has: {
260
295
  * import { get } from "effect/ReadonlyRecord"
261
296
  * import { some, none } from "effect/Option"
262
297
  *
263
- * const person = { name: "John Doe", age: 35 }
298
+ * const person: Record<string, unknown> = { name: "John Doe", age: 35 }
264
299
  *
265
300
  * assert.deepStrictEqual(get(person, "name"), some("John Doe"))
266
301
  * assert.deepStrictEqual(get(person, "email"), none())
@@ -268,11 +303,12 @@ export const has: {
268
303
  * @since 2.0.0
269
304
  */
270
305
  export const get: {
271
- (key: string): <A>(self: ReadonlyRecord<A>) => Option.Option<A>
272
- <A>(self: ReadonlyRecord<A>, key: string): Option.Option<A>
306
+ <K extends string | symbol>(key: NoInfer<K>): <A>(self: ReadonlyRecord<K, A>) => Option.Option<A>
307
+ <K extends string | symbol, A>(self: ReadonlyRecord<K, A>, key: NoInfer<K>): Option.Option<A>
273
308
  } = dual(
274
309
  2,
275
- <A>(self: ReadonlyRecord<A>, key: string): Option.Option<A> => has(self, key) ? Option.some(self[key]) : Option.none()
310
+ <K extends string | symbol, A>(self: ReadonlyRecord<K, A>, key: NoInfer<K>): Option.Option<A> =>
311
+ has(self, key) ? Option.some(self[key]) : Option.none()
276
312
  )
277
313
 
278
314
  /**
@@ -294,21 +330,21 @@ export const get: {
294
330
  * { a: 6 }
295
331
  * )
296
332
  * assert.deepStrictEqual(
297
- * modify({ a: 3 }, 'b', f),
333
+ * modify({ a: 3 } as Record<string, number>, 'b', f),
298
334
  * { a: 3 }
299
335
  * )
300
336
  *
301
337
  * @since 2.0.0
302
338
  */
303
339
  export const modify: {
304
- <A, B>(
305
- key: string,
340
+ <K extends string | symbol, A, B>(
341
+ key: NoInfer<K>,
306
342
  f: (a: A) => B
307
- ): (self: ReadonlyRecord<A>) => Record<string, A | B>
308
- <A, B>(self: ReadonlyRecord<A>, key: string, f: (a: A) => B): Record<string, A | B>
343
+ ): (self: ReadonlyRecord<K, A>) => Record<K, A | B>
344
+ <K extends string | symbol, A, B>(self: ReadonlyRecord<K, A>, key: NoInfer<K>, f: (a: A) => B): Record<K, A | B>
309
345
  } = dual(
310
346
  3,
311
- <A, B>(self: ReadonlyRecord<A>, key: string, f: (a: A) => B): Record<string, A | B> => {
347
+ <K extends string | symbol, A, B>(self: ReadonlyRecord<K, A>, key: NoInfer<K>, f: (a: A) => B): Record<K, A | B> => {
312
348
  if (!has(self, key)) {
313
349
  return { ...self }
314
350
  }
@@ -335,24 +371,33 @@ export const modify: {
335
371
  * some({ a: 6 })
336
372
  * )
337
373
  * assert.deepStrictEqual(
338
- * modifyOption({ a: 3 }, 'b', f),
374
+ * modifyOption({ a: 3 } as Record<string, number>, 'b', f),
339
375
  * none()
340
376
  * )
341
377
  *
342
378
  * @since 2.0.0
343
379
  */
344
380
  export const modifyOption: {
345
- <A, B>(key: string, f: (a: A) => B): (self: ReadonlyRecord<A>) => Option.Option<Record<string, A | B>>
346
- <A, B>(self: ReadonlyRecord<A>, key: string, f: (a: A) => B): Option.Option<Record<string, A | B>>
381
+ <K extends string | symbol, A, B>(
382
+ key: NoInfer<K>,
383
+ f: (a: A) => B
384
+ ): (self: ReadonlyRecord<K, A>) => Option.Option<Record<K, A | B>>
385
+ <K extends string | symbol, A, B>(
386
+ self: ReadonlyRecord<K, A>,
387
+ key: NoInfer<K>,
388
+ f: (a: A) => B
389
+ ): Option.Option<Record<K, A | B>>
347
390
  } = dual(
348
391
  3,
349
- <A, B>(self: ReadonlyRecord<A>, key: string, f: (a: A) => B): Option.Option<Record<string, A | B>> => {
392
+ <K extends string | symbol, A, B>(
393
+ self: ReadonlyRecord<K, A>,
394
+ key: NoInfer<K>,
395
+ f: (a: A) => B
396
+ ): Option.Option<Record<K, A | B>> => {
350
397
  if (!has(self, key)) {
351
398
  return Option.none()
352
399
  }
353
- const out: Record<string, A | B> = { ...self }
354
- out[key] = f(self[key])
355
- return Option.some(out)
400
+ return Option.some({ ...self, [key]: f(self[key]) })
356
401
  }
357
402
  )
358
403
 
@@ -364,28 +409,39 @@ export const modifyOption: {
364
409
  * @param b - The new value to replace the existing value with.
365
410
  *
366
411
  * @example
367
- * import { replaceOption } from "effect/ReadonlyRecord"
412
+ * import { empty, replaceOption } from "effect/ReadonlyRecord"
368
413
  * import { some, none } from "effect/Option"
369
414
  *
370
415
  * assert.deepStrictEqual(
371
416
  * replaceOption({ a: 1, b: 2, c: 3 }, 'a', 10),
372
417
  * some({ a: 10, b: 2, c: 3 })
373
418
  * )
374
- * assert.deepStrictEqual(replaceOption({}, 'a', 10), none())
419
+ * assert.deepStrictEqual(replaceOption(empty<string>(), 'a', 10), none())
375
420
  *
376
421
  * @since 2.0.0
377
422
  */
378
423
  export const replaceOption: {
379
- <B>(key: string, b: B): <A>(self: ReadonlyRecord<A>) => Option.Option<Record<string, A | B>>
380
- <A, B>(self: ReadonlyRecord<A>, key: string, b: B): Option.Option<Record<string, A | B>>
424
+ <K extends string | symbol, B>(
425
+ key: NoInfer<K>,
426
+ b: B
427
+ ): <A>(self: ReadonlyRecord<K, A>) => Option.Option<Record<K, A | B>>
428
+ <K extends string | symbol, A, B>(
429
+ self: ReadonlyRecord<K, A>,
430
+ key: NoInfer<K>,
431
+ b: B
432
+ ): Option.Option<Record<K, A | B>>
381
433
  } = dual(
382
434
  3,
383
- <A, B>(self: ReadonlyRecord<A>, key: string, b: B): Option.Option<Record<string, A | B>> =>
384
- modifyOption(self, key, () => b)
435
+ <K extends string | symbol, A, B>(
436
+ self: ReadonlyRecord<K, A>,
437
+ key: NoInfer<K>,
438
+ b: B
439
+ ): Option.Option<Record<K, A | B>> => modifyOption(self, key, () => b)
385
440
  )
386
441
 
387
442
  /**
388
- * Removes a key from a record and returns a new record
443
+ * If the given key exists in the record, returns a new record with the key removed,
444
+ * otherwise returns a copy of the original record.
389
445
  *
390
446
  * @param self - the record to remove the key from.
391
447
  * @param key - the key to remove from the record.
@@ -398,13 +454,19 @@ export const replaceOption: {
398
454
  * @since 2.0.0
399
455
  */
400
456
  export const remove: {
401
- (key: string): <A>(self: ReadonlyRecord<A>) => Record<string, A>
402
- <A>(self: ReadonlyRecord<A>, key: string): Record<string, A>
403
- } = dual(2, <A>(self: ReadonlyRecord<A>, key: string): Record<string, A> => {
404
- const out = { ...self }
405
- delete out[key]
406
- return out
407
- })
457
+ <K extends string | symbol, X extends K>(key: X): <A>(self: ReadonlyRecord<K, A>) => Record<Exclude<K, X>, A>
458
+ <K extends string | symbol, A, X extends K>(self: ReadonlyRecord<K, A>, key: X): Record<Exclude<K, X>, A>
459
+ } = dual(
460
+ 2,
461
+ <K extends string | symbol, A, X extends K>(self: ReadonlyRecord<K, A>, key: X): Record<Exclude<K, X>, A> => {
462
+ if (!has(self, key)) {
463
+ return { ...self }
464
+ }
465
+ const out = { ...self }
466
+ delete out[key]
467
+ return out
468
+ }
469
+ )
408
470
 
409
471
  /**
410
472
  * Retrieves the value of the property with the given `key` from a record and returns an `Option`
@@ -419,18 +481,23 @@ export const remove: {
419
481
  * import { some, none } from 'effect/Option'
420
482
  *
421
483
  * assert.deepStrictEqual(pop({ a: 1, b: 2 }, "a"), some([1, { b: 2 }]))
422
- * assert.deepStrictEqual(pop({ a: 1, b: 2 }, "c"), none())
484
+ * assert.deepStrictEqual(pop({ a: 1, b: 2 } as Record<string, number>, "c"), none())
423
485
  *
424
486
  * @category record
425
487
  * @since 2.0.0
426
488
  */
427
489
  export const pop: {
428
- (key: string): <A>(self: ReadonlyRecord<A>) => Option.Option<[A, Record<string, A>]>
429
- <A>(self: ReadonlyRecord<A>, key: string): Option.Option<[A, Record<string, A>]>
430
- } = dual(2, <A>(
431
- self: ReadonlyRecord<A>,
432
- key: string
433
- ): Option.Option<[A, Record<string, A>]> =>
490
+ <K extends string | symbol, X extends K>(
491
+ key: X
492
+ ): <A>(self: ReadonlyRecord<K, A>) => Option.Option<[A, Record<Exclude<K, X>, A>]>
493
+ <K extends string | symbol, A, X extends K>(
494
+ self: ReadonlyRecord<K, A>,
495
+ key: X
496
+ ): Option.Option<[A, Record<Exclude<K, X>, A>]>
497
+ } = dual(2, <K extends string | symbol, A, X extends K>(
498
+ self: ReadonlyRecord<K, A>,
499
+ key: X
500
+ ): Option.Option<[A, Record<Exclude<K, X>, A>]> =>
434
501
  has(self, key) ? Option.some([self[key], remove(self, key)]) : Option.none())
435
502
 
436
503
  /**
@@ -454,13 +521,13 @@ export const pop: {
454
521
  * @since 2.0.0
455
522
  */
456
523
  export const map: {
457
- <K extends string, A, B>(f: (a: A, key: K) => B): (self: Record<K, A>) => Record<K, B>
458
- <K extends string, A, B>(self: Record<K, A>, f: (a: A, key: K) => B): Record<K, B>
524
+ <K extends string, A, B>(f: (a: A, key: NoInfer<K>) => B): (self: ReadonlyRecord<K, A>) => Record<K, B>
525
+ <K extends string, A, B>(self: ReadonlyRecord<K, A>, f: (a: A, key: NoInfer<K>) => B): Record<K, B>
459
526
  } = dual(
460
527
  2,
461
- <A, B>(self: ReadonlyRecord<A>, f: (a: A, key: string) => B): Record<string, B> => {
462
- const out: Record<string, B> = {}
463
- for (const key of Object.keys(self)) {
528
+ <K extends string, A, B>(self: ReadonlyRecord<K, A>, f: (a: A, key: NoInfer<K>) => B): Record<K, B> => {
529
+ const out: Record<K, B> = { ...self } as any
530
+ for (const key of keys(self)) {
464
531
  out[key] = f(self[key], key)
465
532
  }
466
533
  return out
@@ -479,13 +546,21 @@ export const map: {
479
546
  * @since 2.0.0
480
547
  */
481
548
  export const mapKeys: {
482
- <A>(f: (key: string, a: A) => string): (self: ReadonlyRecord<A>) => Record<string, A>
483
- <A>(self: ReadonlyRecord<A>, f: (key: string, a: A) => string): Record<string, A>
549
+ <K extends string, A, K2 extends string>(
550
+ f: (key: K, a: A) => K2
551
+ ): (self: ReadonlyRecord<K, A>) => Record<K2, A>
552
+ <K extends string, A, K2 extends string>(
553
+ self: ReadonlyRecord<K, A>,
554
+ f: (key: K, a: A) => K2
555
+ ): Record<K2, A>
484
556
  } = dual(
485
557
  2,
486
- <A>(self: ReadonlyRecord<A>, f: (key: string, a: A) => string): Record<string, A> => {
487
- const out: Record<string, A> = {}
488
- for (const key of Object.keys(self)) {
558
+ <K extends string, A, K2 extends string>(
559
+ self: ReadonlyRecord<K, A>,
560
+ f: (key: K, a: A) => K2
561
+ ): Record<K2, A> => {
562
+ const out: Record<K2, A> = {} as any
563
+ for (const key of keys(self)) {
489
564
  const a = self[key]
490
565
  out[f(key, a)] = a
491
566
  }
@@ -505,15 +580,23 @@ export const mapKeys: {
505
580
  * @since 2.0.0
506
581
  */
507
582
  export const mapEntries: {
508
- <A>(f: (a: A, key: string) => [string, A]): (self: ReadonlyRecord<A>) => Record<string, A>
509
- <A>(self: ReadonlyRecord<A>, f: (a: A, key: string) => [string, A]): Record<string, A>
583
+ <K extends string, A, K2 extends string, B>(
584
+ f: (a: A, key: K) => readonly [K2, B]
585
+ ): (self: ReadonlyRecord<K, A>) => Record<K2, B>
586
+ <K extends string, A, K2 extends string, B>(
587
+ self: ReadonlyRecord<K, A>,
588
+ f: (a: A, key: K) => [K2, B]
589
+ ): Record<K2, B>
510
590
  } = dual(
511
591
  2,
512
- <A>(self: ReadonlyRecord<A>, f: (a: A, key: string) => [string, A]): Record<string, A> => {
513
- const out: Record<string, A> = {}
514
- for (const key of Object.keys(self)) {
515
- const [k, a] = f(self[key], key)
516
- out[k] = a
592
+ <K extends string, A, K2 extends string, B>(
593
+ self: ReadonlyRecord<K, A>,
594
+ f: (a: A, key: K) => [K2, B]
595
+ ): Record<K2, B> => {
596
+ const out = <Record<K2, B>> {}
597
+ for (const key of keys(self)) {
598
+ const [k, b] = f(self[key], key)
599
+ out[k] = b
517
600
  }
518
601
  return out
519
602
  }
@@ -537,21 +620,29 @@ export const mapEntries: {
537
620
  * @since 2.0.0
538
621
  */
539
622
  export const filterMap: {
540
- <K extends string, A, B>(f: (a: A, key: K) => Option.Option<B>): (self: Record<K, A>) => Record<string, B>
541
- <K extends string, A, B>(self: Record<K, A>, f: (a: A, key: K) => Option.Option<B>): Record<string, B>
542
- } = dual(2, <A, B>(
543
- self: Record<string, A>,
544
- f: (a: A, key: string) => Option.Option<B>
545
- ): Record<string, B> => {
546
- const out: Record<string, B> = {}
547
- for (const key of Object.keys(self)) {
548
- const o = f(self[key], key)
549
- if (Option.isSome(o)) {
550
- out[key] = o.value
623
+ <K extends string, A, B>(
624
+ f: (a: A, key: K) => Option.Option<B>
625
+ ): (self: ReadonlyRecord<K, A>) => Record<ReadonlyRecord.NonLiteralKey<K>, B>
626
+ <K extends string, A, B>(
627
+ self: ReadonlyRecord<K, A>,
628
+ f: (a: A, key: K) => Option.Option<B>
629
+ ): Record<ReadonlyRecord.NonLiteralKey<K>, B>
630
+ } = dual(
631
+ 2,
632
+ <K extends string, A, B>(
633
+ self: ReadonlyRecord<K, A>,
634
+ f: (a: A, key: K) => Option.Option<B>
635
+ ): Record<ReadonlyRecord.NonLiteralKey<K>, B> => {
636
+ const out: Record<string, B> = empty()
637
+ for (const key of keys(self)) {
638
+ const o = f(self[key], key)
639
+ if (Option.isSome(o)) {
640
+ out[key] = o.value
641
+ }
551
642
  }
643
+ return out
552
644
  }
553
- return out
554
- })
645
+ )
555
646
 
556
647
  /**
557
648
  * Selects properties from a record whose values match the given predicate.
@@ -571,20 +662,26 @@ export const filterMap: {
571
662
  export const filter: {
572
663
  <K extends string, A, B extends A>(
573
664
  refinement: (a: NoInfer<A>, key: K) => a is B
574
- ): (self: Record<K, A>) => Record<string, B>
665
+ ): (self: ReadonlyRecord<K, A>) => Record<ReadonlyRecord.NonLiteralKey<K>, B>
575
666
  <K extends string, A>(
576
667
  predicate: (A: NoInfer<A>, key: K) => boolean
577
- ): (self: Record<K, A>) => Record<string, A>
578
- <K extends string, A, B extends A>(self: Record<K, A>, refinement: (a: A, key: K) => a is B): Record<string, B>
579
- <K extends string, A>(self: Record<K, A>, predicate: (a: A, key: K) => boolean): Record<string, A>
668
+ ): (self: ReadonlyRecord<K, A>) => Record<ReadonlyRecord.NonLiteralKey<K>, A>
669
+ <K extends string, A, B extends A>(
670
+ self: ReadonlyRecord<K, A>,
671
+ refinement: (a: A, key: K) => a is B
672
+ ): Record<ReadonlyRecord.NonLiteralKey<K>, B>
673
+ <K extends string, A>(
674
+ self: ReadonlyRecord<K, A>,
675
+ predicate: (a: A, key: K) => boolean
676
+ ): Record<ReadonlyRecord.NonLiteralKey<K>, A>
580
677
  } = dual(
581
678
  2,
582
- <A>(
583
- self: Record<string, A>,
584
- predicate: (a: A, key: string) => boolean
585
- ): Record<string, A> => {
586
- const out: Record<string, A> = {}
587
- for (const key of Object.keys(self)) {
679
+ <K extends string, A>(
680
+ self: ReadonlyRecord<K, A>,
681
+ predicate: (a: A, key: K) => boolean
682
+ ): Record<ReadonlyRecord.NonLiteralKey<K>, A> => {
683
+ const out: Record<string, A> = empty()
684
+ for (const key of keys(self)) {
588
685
  if (predicate(self[key], key)) {
589
686
  out[key] = self[key]
590
687
  }
@@ -610,7 +707,9 @@ export const filter: {
610
707
  * @category filtering
611
708
  * @since 2.0.0
612
709
  */
613
- export const getSomes: <A>(self: ReadonlyRecord<Option.Option<A>>) => Record<string, A> = filterMap(
710
+ export const getSomes: <K extends string, A>(
711
+ self: ReadonlyRecord<K, Option.Option<A>>
712
+ ) => Record<ReadonlyRecord.NonLiteralKey<K>, A> = filterMap(
614
713
  identity
615
714
  )
616
715
 
@@ -629,9 +728,11 @@ export const getSomes: <A>(self: ReadonlyRecord<Option.Option<A>>) => Record<str
629
728
  * @category filtering
630
729
  * @since 2.0.0
631
730
  */
632
- export const getLefts = <E, A>(self: ReadonlyRecord<Either<E, A>>): Record<string, E> => {
633
- const out: Record<string, E> = {}
634
- for (const key of Object.keys(self)) {
731
+ export const getLefts = <K extends string, R, L>(
732
+ self: ReadonlyRecord<K, Either<R, L>>
733
+ ): Record<ReadonlyRecord.NonLiteralKey<K>, L> => {
734
+ const out: Record<string, L> = empty()
735
+ for (const key of keys(self)) {
635
736
  const value = self[key]
636
737
  if (E.isLeft(value)) {
637
738
  out[key] = value.left
@@ -656,9 +757,11 @@ export const getLefts = <E, A>(self: ReadonlyRecord<Either<E, A>>): Record<strin
656
757
  * @category filtering
657
758
  * @since 2.0.0
658
759
  */
659
- export const getRights = <E, A>(self: ReadonlyRecord<Either<E, A>>): Record<string, A> => {
660
- const out: Record<string, A> = {}
661
- for (const key of Object.keys(self)) {
760
+ export const getRights = <K extends string, R, L>(
761
+ self: ReadonlyRecord<K, Either<R, L>>
762
+ ): Record<string, R> => {
763
+ const out: Record<string, R> = empty()
764
+ for (const key of keys(self)) {
662
765
  const value = self[key]
663
766
  if (E.isRight(value)) {
664
767
  out[key] = value.right
@@ -687,21 +790,23 @@ export const getRights = <E, A>(self: ReadonlyRecord<Either<E, A>>): Record<stri
687
790
  */
688
791
  export const partitionMap: {
689
792
  <K extends string, A, B, C>(
690
- f: (a: A, key: K) => Either<B, C>
691
- ): (self: Record<K, A>) => [left: Record<string, B>, right: Record<string, C>]
793
+ f: (a: A, key: K) => Either<C, B>
794
+ ): (
795
+ self: ReadonlyRecord<K, A>
796
+ ) => [left: Record<ReadonlyRecord.NonLiteralKey<K>, B>, right: Record<ReadonlyRecord.NonLiteralKey<K>, C>]
692
797
  <K extends string, A, B, C>(
693
- self: Record<K, A>,
694
- f: (a: A, key: K) => Either<B, C>
695
- ): [left: Record<string, B>, right: Record<string, C>]
798
+ self: ReadonlyRecord<K, A>,
799
+ f: (a: A, key: K) => Either<C, B>
800
+ ): [left: Record<ReadonlyRecord.NonLiteralKey<K>, B>, right: Record<ReadonlyRecord.NonLiteralKey<K>, C>]
696
801
  } = dual(
697
802
  2,
698
- <A, B, C>(
699
- self: Record<string, A>,
700
- f: (a: A, key: string) => Either<B, C>
701
- ): [left: Record<string, B>, right: Record<string, C>] => {
702
- const left: Record<string, B> = {}
703
- const right: Record<string, C> = {}
704
- for (const key of Object.keys(self)) {
803
+ <K extends string, A, B, C>(
804
+ self: ReadonlyRecord<K, A>,
805
+ f: (a: A, key: K) => Either<C, B>
806
+ ): [left: Record<ReadonlyRecord.NonLiteralKey<K>, B>, right: Record<ReadonlyRecord.NonLiteralKey<K>, C>] => {
807
+ const left: Record<string, B> = empty()
808
+ const right: Record<string, C> = empty()
809
+ for (const key of keys(self)) {
705
810
  const e = f(self[key], key)
706
811
  if (E.isLeft(e)) {
707
812
  left[key] = e.left
@@ -731,9 +836,9 @@ export const partitionMap: {
731
836
  * @category filtering
732
837
  * @since 2.0.0
733
838
  */
734
- export const separate: <A, B>(
735
- self: ReadonlyRecord<Either<A, B>>
736
- ) => [Record<string, A>, Record<string, B>] = partitionMap(identity)
839
+ export const separate: <K extends string, A, B>(
840
+ self: ReadonlyRecord<K, Either<B, A>>
841
+ ) => [Record<ReadonlyRecord.NonLiteralKey<K>, A>, Record<ReadonlyRecord.NonLiteralKey<K>, B>] = partitionMap(identity)
737
842
 
738
843
  /**
739
844
  * Partitions a record into two separate records based on the result of a predicate function.
@@ -754,28 +859,36 @@ export const separate: <A, B>(
754
859
  */
755
860
  export const partition: {
756
861
  <K extends string, A, B extends A>(refinement: (a: NoInfer<A>, key: K) => a is B): (
757
- self: Record<K, A>
758
- ) => [excluded: Record<string, Exclude<A, B>>, satisfying: Record<string, B>]
862
+ self: ReadonlyRecord<K, A>
863
+ ) => [
864
+ excluded: Record<ReadonlyRecord.NonLiteralKey<K>, Exclude<A, B>>,
865
+ satisfying: Record<ReadonlyRecord.NonLiteralKey<K>, B>
866
+ ]
759
867
  <K extends string, A>(
760
868
  predicate: (a: NoInfer<A>, key: K) => boolean
761
- ): (self: Record<K, A>) => [excluded: Record<string, A>, satisfying: Record<string, A>]
869
+ ): (
870
+ self: ReadonlyRecord<K, A>
871
+ ) => [excluded: Record<ReadonlyRecord.NonLiteralKey<K>, A>, satisfying: Record<ReadonlyRecord.NonLiteralKey<K>, A>]
762
872
  <K extends string, A, B extends A>(
763
- self: Record<K, A>,
873
+ self: ReadonlyRecord<K, A>,
764
874
  refinement: (a: A, key: K) => a is B
765
- ): [excluded: Record<string, Exclude<A, B>>, satisfying: Record<string, B>]
875
+ ): [
876
+ excluded: Record<ReadonlyRecord.NonLiteralKey<K>, Exclude<A, B>>,
877
+ satisfying: Record<ReadonlyRecord.NonLiteralKey<K>, B>
878
+ ]
766
879
  <K extends string, A>(
767
- self: Record<K, A>,
880
+ self: ReadonlyRecord<K, A>,
768
881
  predicate: (a: A, key: K) => boolean
769
- ): [excluded: Record<string, A>, satisfying: Record<string, A>]
882
+ ): [excluded: Record<ReadonlyRecord.NonLiteralKey<K>, A>, satisfying: Record<ReadonlyRecord.NonLiteralKey<K>, A>]
770
883
  } = dual(
771
884
  2,
772
- <A>(
773
- self: Record<string, A>,
774
- predicate: (a: A, key: string) => boolean
775
- ): [excluded: Record<string, A>, satisfying: Record<string, A>] => {
776
- const left: Record<string, A> = {}
777
- const right: Record<string, A> = {}
778
- for (const key of Object.keys(self)) {
885
+ <K extends string, A>(
886
+ self: ReadonlyRecord<K, A>,
887
+ predicate: (a: A, key: K) => boolean
888
+ ): [excluded: Record<ReadonlyRecord.NonLiteralKey<K>, A>, satisfying: Record<ReadonlyRecord.NonLiteralKey<K>, A>] => {
889
+ const left: Record<string, A> = empty()
890
+ const right: Record<string, A> = empty()
891
+ for (const key of keys(self)) {
779
892
  if (predicate(self[key], key)) {
780
893
  right[key] = self[key]
781
894
  } else {
@@ -793,7 +906,7 @@ export const partition: {
793
906
  *
794
907
  * @since 2.0.0
795
908
  */
796
- export const keys = <A>(self: ReadonlyRecord<A>): Array<string> => Object.keys(self)
909
+ export const keys = <K extends string, A>(self: ReadonlyRecord<K, A>): Array<K> => Object.keys(self) as Array<K>
797
910
 
798
911
  /**
799
912
  * Retrieve the values of a given record as an array.
@@ -802,7 +915,7 @@ export const keys = <A>(self: ReadonlyRecord<A>): Array<string> => Object.keys(s
802
915
  *
803
916
  * @since 2.0.0
804
917
  */
805
- export const values = <A>(self: ReadonlyRecord<A>): Array<A> => collect(self, (_, a) => a)
918
+ export const values = <K extends string, A>(self: ReadonlyRecord<K, A>): Array<A> => collect(self, (_, a) => a)
806
919
 
807
920
  /**
808
921
  * Add a new key-value pair or update an existing key's value in a record.
@@ -820,16 +933,29 @@ export const values = <A>(self: ReadonlyRecord<A>): Array<A> => collect(self, (_
820
933
  * @since 2.0.0
821
934
  */
822
935
  export const set: {
823
- <B>(key: string, value: B): <A>(self: ReadonlyRecord<A>) => Record<string, A | B>
824
- <A, B>(self: ReadonlyRecord<A>, key: string, value: B): Record<string, A | B>
825
- } = dual(3, <A, B>(self: ReadonlyRecord<A>, key: string, value: B): Record<string, A | B> => {
826
- const out: Record<string, A | B> = { ...self }
827
- out[key] = value
828
- return out
829
- })
936
+ <K extends string | symbol, K1 extends K | ((string | symbol) & {}), B>(
937
+ key: K1,
938
+ value: B
939
+ ): <A>(self: ReadonlyRecord<K, A>) => Record<K | K1, A | B>
940
+ <K extends string | symbol, A, K1 extends K | ((string | symbol) & {}), B>(
941
+ self: ReadonlyRecord<K, A>,
942
+ key: K1,
943
+ value: B
944
+ ): Record<K | K1, A | B>
945
+ } = dual(
946
+ 3,
947
+ <K extends string | symbol, A, K1 extends K | ((string | symbol) & {}), B>(
948
+ self: ReadonlyRecord<K, A>,
949
+ key: K1,
950
+ value: B
951
+ ): Record<K | K1, A | B> => {
952
+ return { ...self, [key]: value } as any
953
+ }
954
+ )
830
955
 
831
956
  /**
832
957
  * Replace a key's value in a record and return the updated record.
958
+ * If the key does not exist in the record, a copy of the original record is returned.
833
959
  *
834
960
  * @param self - The original record.
835
961
  * @param key - The key to replace.
@@ -845,15 +971,17 @@ export const set: {
845
971
  * @since 2.0.0
846
972
  */
847
973
  export const replace: {
848
- <B>(key: string, value: B): <A>(self: ReadonlyRecord<A>) => Record<string, A | B>
849
- <A, B>(self: ReadonlyRecord<A>, key: string, value: B): Record<string, A | B>
850
- } = dual(3, <A, B>(self: ReadonlyRecord<A>, key: string, value: B): Record<string, A | B> => {
851
- const out: Record<string, A | B> = { ...self }
852
- if (has(self, key)) {
853
- out[key] = value
974
+ <K extends string | symbol, B>(key: NoInfer<K>, value: B): <A>(self: ReadonlyRecord<K, A>) => Record<K, A | B>
975
+ <K extends string | symbol, A, B>(self: ReadonlyRecord<K, A>, key: NoInfer<K>, value: B): Record<K, A | B>
976
+ } = dual(
977
+ 3,
978
+ <K extends string | symbol, A, B>(self: ReadonlyRecord<K, A>, key: NoInfer<K>, value: B): Record<K, A | B> => {
979
+ if (has(self, key)) {
980
+ return { ...self, [key]: value }
981
+ }
982
+ return { ...self }
854
983
  }
855
- return out
856
- })
984
+ )
857
985
 
858
986
  /**
859
987
  * Check if all the keys and values in one record are also found in another record.
@@ -865,11 +993,11 @@ export const replace: {
865
993
  * @since 2.0.0
866
994
  */
867
995
  export const isSubrecordBy = <A>(equivalence: Equivalence<A>): {
868
- (that: ReadonlyRecord<A>): (self: ReadonlyRecord<A>) => boolean
869
- (self: ReadonlyRecord<A>, that: ReadonlyRecord<A>): boolean
996
+ <K extends string>(that: ReadonlyRecord<K, A>): (self: ReadonlyRecord<K, A>) => boolean
997
+ <K extends string>(self: ReadonlyRecord<K, A>, that: ReadonlyRecord<K, A>): boolean
870
998
  } =>
871
- dual(2, (self: ReadonlyRecord<A>, that: ReadonlyRecord<A>): boolean => {
872
- for (const key in self) {
999
+ dual(2, <K extends string>(self: ReadonlyRecord<K, A>, that: ReadonlyRecord<K, A>): boolean => {
1000
+ for (const key of keys(self)) {
873
1001
  if (!has(that, key) || !equivalence(self[key], that[key])) {
874
1002
  return false
875
1003
  }
@@ -887,8 +1015,8 @@ export const isSubrecordBy = <A>(equivalence: Equivalence<A>): {
887
1015
  * @since 2.0.0
888
1016
  */
889
1017
  export const isSubrecord: {
890
- <A>(that: ReadonlyRecord<A>): (self: ReadonlyRecord<A>) => boolean
891
- <A>(self: ReadonlyRecord<A>, that: ReadonlyRecord<A>): boolean
1018
+ <K extends string, A>(that: ReadonlyRecord<K, A>): (self: ReadonlyRecord<K, A>) => boolean
1019
+ <K extends string, A>(self: ReadonlyRecord<K, A>, that: ReadonlyRecord<K, A>): boolean
892
1020
  } = isSubrecordBy(Equal.equivalence())
893
1021
 
894
1022
  /**
@@ -902,15 +1030,25 @@ export const isSubrecord: {
902
1030
  * @since 2.0.0
903
1031
  */
904
1032
  export const reduce: {
905
- <Z, V, K extends string>(zero: Z, f: (accumulator: Z, value: V, key: K) => Z): (self: Record<K, V>) => Z
906
- <K extends string, V, Z>(self: Record<K, V>, zero: Z, f: (accumulator: Z, value: V, key: K) => Z): Z
907
- } = dual(3, <V, Z>(self: Record<string, V>, zero: Z, f: (accumulator: Z, value: V, key: string) => Z): Z => {
908
- let out: Z = zero
909
- for (const key in self) {
910
- out = f(out, self[key], key)
1033
+ <Z, V, K extends string>(
1034
+ zero: Z,
1035
+ f: (accumulator: Z, value: V, key: K) => Z
1036
+ ): (self: ReadonlyRecord<K, V>) => Z
1037
+ <K extends string, V, Z>(self: ReadonlyRecord<K, V>, zero: Z, f: (accumulator: Z, value: V, key: K) => Z): Z
1038
+ } = dual(
1039
+ 3,
1040
+ <K extends string, V, Z>(
1041
+ self: ReadonlyRecord<K, V>,
1042
+ zero: Z,
1043
+ f: (accumulator: Z, value: V, key: K) => Z
1044
+ ): Z => {
1045
+ let out: Z = zero
1046
+ for (const key of keys(self)) {
1047
+ out = f(out, self[key], key)
1048
+ }
1049
+ return out
911
1050
  }
912
- return out
913
- })
1051
+ )
914
1052
 
915
1053
  /**
916
1054
  * Check if all entries in a record meet a specific condition.
@@ -923,24 +1061,27 @@ export const reduce: {
923
1061
  export const every: {
924
1062
  <A, K extends string, B extends A>(
925
1063
  refinement: (value: A, key: K) => value is B
926
- ): (self: Record<K, A>) => self is Readonly<Record<K, B>>
927
- <A, K extends string>(predicate: (value: A, key: K) => boolean): (self: Record<K, A>) => boolean
1064
+ ): (self: ReadonlyRecord<K, A>) => self is ReadonlyRecord<K, B>
1065
+ <A, K extends string>(predicate: (value: A, key: K) => boolean): (self: ReadonlyRecord<K, A>) => boolean
1066
+ <A, K extends string, B extends A>(
1067
+ self: ReadonlyRecord<K, A>,
1068
+ refinement: (value: A, key: K) => value is B
1069
+ ): self is ReadonlyRecord<K, B>
1070
+ <K extends string, A>(self: ReadonlyRecord<K, A>, predicate: (value: A, key: K) => boolean): boolean
1071
+ } = dual(
1072
+ 2,
928
1073
  <A, K extends string, B extends A>(
929
- self: Record<K, A>,
1074
+ self: ReadonlyRecord<K, A>,
930
1075
  refinement: (value: A, key: K) => value is B
931
- ): self is Readonly<Record<K, B>>
932
- <K extends string, A>(self: Record<K, A>, predicate: (value: A, key: K) => boolean): boolean
933
- } = dual(2, <A, K extends string, B extends A>(
934
- self: Record<K, A>,
935
- refinement: (value: A, key: K) => value is B
936
- ): self is Readonly<Record<K, A>> => {
937
- for (const key in self) {
938
- if (!refinement(self[key], key)) {
939
- return false
1076
+ ): self is ReadonlyRecord<K, B> => {
1077
+ for (const key of keys(self)) {
1078
+ if (!refinement(self[key], key)) {
1079
+ return false
1080
+ }
940
1081
  }
1082
+ return true
941
1083
  }
942
- return true
943
- })
1084
+ )
944
1085
 
945
1086
  /**
946
1087
  * Check if any entry in a record meets a specific condition.
@@ -951,16 +1092,19 @@ export const every: {
951
1092
  * @since 2.0.0
952
1093
  */
953
1094
  export const some: {
954
- <A, K extends string>(predicate: (value: A, key: K) => boolean): (self: Record<K, A>) => boolean
955
- <K extends string, A>(self: Record<K, A>, predicate: (value: A, key: K) => boolean): boolean
956
- } = dual(2, <K extends string, A>(self: Record<K, A>, predicate: (value: A, key: K) => boolean): boolean => {
957
- for (const key in self) {
958
- if (predicate(self[key], key)) {
959
- return true
1095
+ <A, K extends string>(predicate: (value: A, key: K) => boolean): (self: ReadonlyRecord<K, A>) => boolean
1096
+ <K extends string, A>(self: ReadonlyRecord<K, A>, predicate: (value: A, key: K) => boolean): boolean
1097
+ } = dual(
1098
+ 2,
1099
+ <K extends string, A>(self: ReadonlyRecord<K, A>, predicate: (value: A, key: K) => boolean): boolean => {
1100
+ for (const key of keys(self)) {
1101
+ if (predicate(self[key], key)) {
1102
+ return true
1103
+ }
960
1104
  }
1105
+ return false
961
1106
  }
962
- return false
963
- })
1107
+ )
964
1108
 
965
1109
  /**
966
1110
  * Merge two records, preserving entries that exist in either of the records.
@@ -972,37 +1116,37 @@ export const some: {
972
1116
  * @since 2.0.0
973
1117
  */
974
1118
  export const union: {
975
- <K1 extends string, V0, V1>(
976
- that: Record<K1, V1>,
977
- combine: (selfValue: V0, thatValue: V1) => V0 | V1
978
- ): <K0 extends string>(self: Record<K0, V0>) => Record<K0 | K1, V0 | V1>
979
- <K0 extends string, V0, K1 extends string, V1>(
980
- self: Record<K0, V0>,
981
- that: Record<K1, V1>,
982
- combine: (selfValue: V0, thatValue: V1) => V0 | V1
983
- ): Record<K0 | K1, V0 | V1>
1119
+ <K1 extends string, A, B, C>(
1120
+ that: ReadonlyRecord<K1, B>,
1121
+ combine: (selfValue: A, thatValue: B) => C
1122
+ ): <K0 extends string>(self: ReadonlyRecord<K0, A>) => Record<K0 | K1, A | B | C>
1123
+ <K0 extends string, A, K1 extends string, B, C>(
1124
+ self: ReadonlyRecord<K0, A>,
1125
+ that: ReadonlyRecord<K1, B>,
1126
+ combine: (selfValue: A, thatValue: B) => C
1127
+ ): Record<K0 | K1, A | B | C>
984
1128
  } = dual(
985
1129
  3,
986
- <A>(
987
- self: Record<string, A>,
988
- that: Record<string, A>,
989
- combine: (selfValue: A, thatValue: A) => A
990
- ): Record<string, A> => {
1130
+ <K0 extends string, A, K1 extends string, B, C>(
1131
+ self: ReadonlyRecord<K0, A>,
1132
+ that: ReadonlyRecord<K1, B>,
1133
+ combine: (selfValue: A, thatValue: B) => C
1134
+ ): Record<K0 | K1, A | B | C> => {
991
1135
  if (isEmptyRecord(self)) {
992
- return { ...that }
1136
+ return { ...that } as any
993
1137
  }
994
1138
  if (isEmptyRecord(that)) {
995
- return { ...self }
1139
+ return { ...self } as any
996
1140
  }
997
- const out: Record<string, A> = {}
998
- for (const key in self) {
999
- if (has(that, key)) {
1000
- out[key] = combine(self[key], that[key])
1141
+ const out: Record<string, A | B | C> = empty()
1142
+ for (const key of keys(self)) {
1143
+ if (has(that, key as any)) {
1144
+ out[key] = combine(self[key], that[key as unknown as K1])
1001
1145
  } else {
1002
1146
  out[key] = self[key]
1003
1147
  }
1004
1148
  }
1005
- for (const key in that) {
1149
+ for (const key of keys(that)) {
1006
1150
  if (!has(out, key)) {
1007
1151
  out[key] = that[key]
1008
1152
  }
@@ -1021,25 +1165,29 @@ export const union: {
1021
1165
  * @since 2.0.0
1022
1166
  */
1023
1167
  export const intersection: {
1024
- <A>(
1025
- that: ReadonlyRecord<A>,
1026
- combine: (selfValue: A, thatValue: A) => A
1027
- ): (self: ReadonlyRecord<A>) => Record<string, A>
1028
- <A>(self: ReadonlyRecord<A>, that: ReadonlyRecord<A>, combine: (selfValue: A, thatValue: A) => A): Record<string, A>
1168
+ <K1 extends string, A, B, C>(
1169
+ that: ReadonlyRecord<K1, B>,
1170
+ combine: (selfValue: A, thatValue: B) => C
1171
+ ): <K0 extends string>(self: ReadonlyRecord<K0, A>) => Record<ReadonlyRecord.IntersectKeys<K0, K1>, C>
1172
+ <K0 extends string, A, K1 extends string, B, C>(
1173
+ self: ReadonlyRecord<K0, A>,
1174
+ that: ReadonlyRecord<K1, B>,
1175
+ combine: (selfValue: A, thatValue: B) => C
1176
+ ): Record<ReadonlyRecord.IntersectKeys<K0, K1>, C>
1029
1177
  } = dual(
1030
1178
  3,
1031
- <A>(
1032
- self: ReadonlyRecord<A>,
1033
- that: ReadonlyRecord<A>,
1034
- combine: (selfValue: A, thatValue: A) => A
1035
- ): Record<string, A> => {
1179
+ <K0 extends string, A, K1 extends string, B, C>(
1180
+ self: ReadonlyRecord<K0, A>,
1181
+ that: ReadonlyRecord<K1, B>,
1182
+ combine: (selfValue: A, thatValue: B) => C
1183
+ ): Record<ReadonlyRecord.IntersectKeys<K0, K1>, C> => {
1184
+ const out: Record<string, C> = empty()
1036
1185
  if (isEmptyRecord(self) || isEmptyRecord(that)) {
1037
- return empty()
1186
+ return out
1038
1187
  }
1039
- const out: Record<string, A> = {}
1040
- for (const key in self) {
1041
- if (has(that, key)) {
1042
- out[key] = combine(self[key], that[key])
1188
+ for (const key of keys(self)) {
1189
+ if (has(that, key as any)) {
1190
+ out[key] = combine(self[key], that[key as unknown as K1])
1043
1191
  }
1044
1192
  }
1045
1193
  return out
@@ -1055,25 +1203,31 @@ export const intersection: {
1055
1203
  * @since 2.0.0
1056
1204
  */
1057
1205
  export const difference: {
1058
- <A>(
1059
- that: ReadonlyRecord<A>
1060
- ): (self: ReadonlyRecord<A>) => Record<string, A>
1061
- <A>(self: ReadonlyRecord<A>, that: ReadonlyRecord<A>): Record<string, A>
1062
- } = dual(2, <A>(self: ReadonlyRecord<A>, that: ReadonlyRecord<A>): Record<string, A> => {
1206
+ <K1 extends string, B>(
1207
+ that: ReadonlyRecord<K1, B>
1208
+ ): <K0 extends string, A>(self: ReadonlyRecord<K0, A>) => Record<K0 | K1, A | B>
1209
+ <K0 extends string, A, K1 extends string, B>(
1210
+ self: ReadonlyRecord<K0, A>,
1211
+ that: ReadonlyRecord<K1, B>
1212
+ ): Record<K0 | K1, A | B>
1213
+ } = dual(2, <K0 extends string, A, K1 extends string, B>(
1214
+ self: ReadonlyRecord<K0, A>,
1215
+ that: ReadonlyRecord<K1, B>
1216
+ ): Record<K0 | K1, A | B> => {
1063
1217
  if (isEmptyRecord(self)) {
1064
- return { ...that }
1218
+ return { ...that } as any
1065
1219
  }
1066
1220
  if (isEmptyRecord(that)) {
1067
- return { ...self }
1221
+ return { ...self } as any
1068
1222
  }
1069
- const out: Record<string, A> = {}
1070
- for (const key in self) {
1071
- if (!has(that, key)) {
1223
+ const out = <Record<K0 | K1, A | B>> {}
1224
+ for (const key of keys(self)) {
1225
+ if (!has(that, key as any)) {
1072
1226
  out[key] = self[key]
1073
1227
  }
1074
1228
  }
1075
- for (const key in that) {
1076
- if (!has(self, key)) {
1229
+ for (const key of keys(that)) {
1230
+ if (!has(self, key as any)) {
1077
1231
  out[key] = that[key]
1078
1232
  }
1079
1233
  }
@@ -1088,7 +1242,9 @@ export const difference: {
1088
1242
  * @category instances
1089
1243
  * @since 2.0.0
1090
1244
  */
1091
- export const getEquivalence = <A>(equivalence: Equivalence<A>): Equivalence<ReadonlyRecord<A>> => {
1245
+ export const getEquivalence = <K extends string, A>(
1246
+ equivalence: Equivalence<A>
1247
+ ): Equivalence<ReadonlyRecord<K, A>> => {
1092
1248
  const is = isSubrecordBy(equivalence)
1093
1249
  return (self, that) => is(self, that) && is(that, self)
1094
1250
  }
@@ -1102,6 +1258,6 @@ export const getEquivalence = <A>(equivalence: Equivalence<A>): Equivalence<Read
1102
1258
  * @category constructors
1103
1259
  * @since 2.0.0
1104
1260
  */
1105
- export const singleton = <K extends string, A>(key: K, value: A): Record<K, A> => (({
1261
+ export const singleton = <K extends string | symbol, A>(key: K, value: A): Record<K, A> => ({
1106
1262
  [key]: value
1107
- }) as Record<K, A>)
1263
+ } as any)