1 | import {NOTHING} from "../internal"
|
2 |
|
3 | type AnyFunc = (...args: any[]) => any
|
4 |
|
5 | type PrimitiveType = number | string | boolean
|
6 |
|
7 |
|
8 | type AtomicObject = Function | Promise<any> | Date | RegExp
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | export type IfAvailable<T, Fallback = void> =
|
18 |
|
19 | true | false extends (T extends never
|
20 | ? true
|
21 | : false)
|
22 | ? Fallback
|
23 | : keyof T extends never
|
24 | ? Fallback
|
25 | : T
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | type WeakReferences = IfAvailable<WeakMap<any, any>> | IfAvailable<WeakSet<any>>
|
32 |
|
33 | export type WritableDraft<T> = {-readonly [K in keyof T]: Draft<T[K]>}
|
34 |
|
35 |
|
36 | export type Draft<T> = T extends PrimitiveType
|
37 | ? T
|
38 | : T extends AtomicObject
|
39 | ? T
|
40 | : T extends ReadonlyMap<infer K, infer V>
|
41 | ? Map<Draft<K>, Draft<V>>
|
42 | : T extends ReadonlySet<infer V>
|
43 | ? Set<Draft<V>>
|
44 | : T extends WeakReferences
|
45 | ? T
|
46 | : T extends object
|
47 | ? WritableDraft<T>
|
48 | : T
|
49 |
|
50 |
|
51 | export type Immutable<T> = T extends PrimitiveType
|
52 | ? T
|
53 | : T extends AtomicObject
|
54 | ? T
|
55 | : T extends ReadonlyMap<infer K, infer V>
|
56 | ? ReadonlyMap<Immutable<K>, Immutable<V>>
|
57 | : T extends ReadonlySet<infer V>
|
58 | ? ReadonlySet<Immutable<V>>
|
59 | : T extends WeakReferences
|
60 | ? T
|
61 | : T extends object
|
62 | ? {readonly [K in keyof T]: Immutable<T[K]>}
|
63 | : T
|
64 |
|
65 | export interface Patch {
|
66 | op: "replace" | "remove" | "add"
|
67 | path: (string | number)[]
|
68 | value?: any
|
69 | }
|
70 |
|
71 | export type PatchListener = (patches: Patch[], inversePatches: Patch[]) => void
|
72 |
|
73 |
|
74 | type FromNothing<T> = T extends typeof NOTHING ? undefined : T
|
75 |
|
76 |
|
77 | export type Produced<Base, Return> = Return extends void
|
78 | ? Base
|
79 | : FromNothing<Return>
|
80 |
|
81 |
|
82 |
|
83 |
|
84 | type PatchesTuple<T> = readonly [T, Patch[], Patch[]]
|
85 |
|
86 | type ValidRecipeReturnType<State> =
|
87 | | State
|
88 | | void
|
89 | | undefined
|
90 | | (State extends undefined ? typeof NOTHING : never)
|
91 |
|
92 | type ReturnTypeWithPatchesIfNeeded<
|
93 | State,
|
94 | UsePatches extends boolean
|
95 | > = UsePatches extends true ? PatchesTuple<State> : State
|
96 |
|
97 |
|
98 |
|
99 |
|
100 | type InferRecipeFromCurried<Curried> = Curried extends (
|
101 | base: infer State,
|
102 | ...rest: infer Args
|
103 | ) => any
|
104 | ? ReturnType<Curried> extends State
|
105 | ? (
|
106 | draft: Draft<State>,
|
107 | ...rest: Args
|
108 | ) => ValidRecipeReturnType<Draft<State>>
|
109 | : never
|
110 | : never
|
111 |
|
112 | type InferInitialStateFromCurried<Curried> = Curried extends (
|
113 | base: infer State,
|
114 | ...rest: any[]
|
115 | ) => any
|
116 | ? State
|
117 | : never
|
118 |
|
119 | type InferCurriedFromRecipe<
|
120 | Recipe,
|
121 | UsePatches extends boolean
|
122 | > = Recipe extends (draft: infer DraftState, ...args: infer RestArgs) => any
|
123 | ? ReturnType<Recipe> extends ValidRecipeReturnType<DraftState>
|
124 | ? (
|
125 | base: Immutable<DraftState>,
|
126 | ...args: RestArgs
|
127 | ) => ReturnTypeWithPatchesIfNeeded<DraftState, UsePatches>
|
128 | : never
|
129 | : never
|
130 |
|
131 | type InferCurriedFromInitialStateAndRecipe<
|
132 | State,
|
133 | Recipe,
|
134 | UsePatches extends boolean
|
135 | > = Recipe extends (
|
136 | draft: Draft<State>,
|
137 | ...rest: infer RestArgs
|
138 | ) => ValidRecipeReturnType<State>
|
139 | ? (
|
140 | base?: State | undefined,
|
141 | ...args: RestArgs
|
142 | ) => ReturnTypeWithPatchesIfNeeded<State, UsePatches>
|
143 | : never
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 | export interface IProduce {
|
165 |
|
166 | <Curried>(
|
167 | recipe: InferRecipeFromCurried<Curried>,
|
168 | initialState?: InferInitialStateFromCurried<Curried>
|
169 | ): Curried
|
170 |
|
171 |
|
172 | <Recipe extends AnyFunc>(recipe: Recipe): InferCurriedFromRecipe<
|
173 | Recipe,
|
174 | false
|
175 | >
|
176 |
|
177 |
|
178 | <State>(
|
179 | recipe: (
|
180 | state: Draft<State>,
|
181 | initialState: State
|
182 | ) => ValidRecipeReturnType<State>
|
183 | ): (state?: State) => State
|
184 | <State, Args extends any[]>(
|
185 | recipe: (
|
186 | state: Draft<State>,
|
187 | ...args: Args
|
188 | ) => ValidRecipeReturnType<State>,
|
189 | initialState: State
|
190 | ): (state?: State, ...args: Args) => State
|
191 | <State>(recipe: (state: Draft<State>) => ValidRecipeReturnType<State>): (
|
192 | state: State
|
193 | ) => State
|
194 | <State, Args extends any[]>(
|
195 | recipe: (state: Draft<State>, ...args: Args) => ValidRecipeReturnType<State>
|
196 | ): (state: State, ...args: Args) => State
|
197 |
|
198 |
|
199 | <State, Recipe extends Function>(
|
200 | recipe: Recipe,
|
201 | initialState: State
|
202 | ): InferCurriedFromInitialStateAndRecipe<State, Recipe, false>
|
203 |
|
204 |
|
205 | <Base, D = Draft<Base>>(
|
206 | base: Base,
|
207 | recipe: (draft: D) => ValidRecipeReturnType<D>,
|
208 | listener?: PatchListener
|
209 | ): Base
|
210 | }
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 | export interface IProduceWithPatches {
|
219 |
|
220 | <Recipe extends AnyFunc>(recipe: Recipe): InferCurriedFromRecipe<Recipe, true>
|
221 | <State, Recipe extends Function>(
|
222 | recipe: Recipe,
|
223 | initialState: State
|
224 | ): InferCurriedFromInitialStateAndRecipe<State, Recipe, true>
|
225 | <Base, D = Draft<Base>>(
|
226 | base: Base,
|
227 | recipe: (draft: D) => ValidRecipeReturnType<D>,
|
228 | listener?: PatchListener
|
229 | ): PatchesTuple<Base>
|
230 | }
|
231 |
|
232 |
|
233 |
|
234 |
|
235 | export type Producer<T> = (draft: Draft<T>) => ValidRecipeReturnType<Draft<T>>
|
236 |
|
237 |
|
238 |
|
239 | export function never_used() {}
|