import {Nothing} from "../internal" type AnyFunc = (...args: any[]) => any type PrimitiveType = number | string | boolean /** Object types that should never be mapped */ type AtomicObject = Function | Promise<any> | Date | RegExp /** * If the lib "ES2105.collections" is not included in tsconfig.json, * types like ReadonlyArray, WeakMap etc. fall back to `any` (specified nowhere) * or `{}` (from the node types), in both cases entering an infite recursion in * pattern matching type mappings * This type can be used to cast these types to `void` in these cases. */ export type IfAvailable<T, Fallback = void> = // fallback if any true | false extends (T extends never ? true : false) ? Fallback // fallback if empty type : keyof T extends never ? Fallback // original type : T /** * These should also never be mapped but must be tested after regular Map and * Set */ type WeakReferences = IfAvailable<WeakMap<any, any>> | IfAvailable<WeakSet<any>> export type WritableDraft<T> = {-readonly [K in keyof T]: Draft<T[K]>} export type Draft<T> = T extends PrimitiveType ? T : T extends AtomicObject ? T : T extends IfAvailable<ReadonlyMap<infer K, infer V>> // Map extends ReadonlyMap ? Map<Draft<K>, Draft<V>> : T extends IfAvailable<ReadonlySet<infer V>> // Set extends ReadonlySet ? Set<Draft<V>> : T extends WeakReferences ? T : T extends object ? WritableDraft<T> : T /** Convert a mutable type into a readonly type */ export type Immutable<T> = T extends PrimitiveType ? T : T extends AtomicObject ? T : T extends IfAvailable<ReadonlyMap<infer K, infer V>> // Map extends ReadonlyMap ? ReadonlyMap<Immutable<K>, Immutable<V>> : T extends IfAvailable<ReadonlySet<infer V>> // Set extends ReadonlySet ? ReadonlySet<Immutable<V>> : T extends WeakReferences ? T : T extends object ? {readonly [K in keyof T]: Immutable<T[K]>} : T export interface Patch { op: "replace" | "remove" | "add" path: (string | number)[] value?: any } export type PatchListener = (patches: Patch[], inversePatches: Patch[]) => void /** Converts `nothing` into `undefined` */ type FromNothing<T> = T extends Nothing ? undefined : T /** The inferred return type of `produce` */ export type Produced<Base, Return> = Return extends void ? Base : Return extends Promise<infer Result> ? Promise<Result extends void ? Base : FromNothing<Result>> : FromNothing<Return> /** * Utility types */ type PatchesTuple<T> = readonly [T, Patch[], Patch[]] type ValidRecipeReturnType<State> = | State | void | undefined | (State extends undefined ? Nothing : never) type ValidRecipeReturnTypePossiblyPromise<State> = | ValidRecipeReturnType<State> | Promise<ValidRecipeReturnType<State>> type PromisifyReturnIfNeeded< State, Recipe extends AnyFunc, UsePatches extends boolean > = ReturnType<Recipe> extends Promise<any> ? Promise<UsePatches extends true ? PatchesTuple<State> : State> : UsePatches extends true ? PatchesTuple<State> : State /** * Core Producer inference */ type InferRecipeFromCurried<Curried> = Curried extends ( base: infer State, ...rest: infer Args ) => any // extra assertion to make sure this is a proper curried function (state, args) => state ? ReturnType<Curried> extends State ? ( draft: Draft<State>, ...rest: Args ) => ValidRecipeReturnType<Draft<State>> : never : never type InferInitialStateFromCurried<Curried> = Curried extends ( base: infer State, ...rest: any[] ) => any // extra assertion to make sure this is a proper curried function (state, args) => state ? State : never type InferCurriedFromRecipe< Recipe, UsePatches extends boolean > = Recipe extends (draft: infer DraftState, ...args: infer RestArgs) => any // verify return type ? ReturnType<Recipe> extends ValidRecipeReturnTypePossiblyPromise<DraftState> ? ( base: Immutable<DraftState>, ...args: RestArgs ) => PromisifyReturnIfNeeded<DraftState, Recipe, UsePatches> // N.b. we return mutable draftstate, in case the recipe's first arg isn't read only, and that isn't expected as output either : never // incorrect return type : never // not a function type InferCurriedFromInitialStateAndRecipe< State, Recipe, UsePatches extends boolean > = Recipe extends ( draft: Draft<State>, ...rest: infer RestArgs ) => ValidRecipeReturnTypePossiblyPromise<State> ? ( base?: State | undefined, ...args: RestArgs ) => PromisifyReturnIfNeeded<State, Recipe, UsePatches> : never // recipe doesn't match initial state /** * The `produce` function takes a value and a "recipe function" (whose * return value often depends on the base state). The recipe function is * free to mutate its first argument however it wants. All mutations are * only ever applied to a __copy__ of the base state. * * Pass only a function to create a "curried producer" which relieves you * from passing the recipe function every time. * * Only plain objects and arrays are made mutable. All other objects are * considered uncopyable. * * Note: This function is __bound__ to its `Immer` instance. * * @param {any} base - the initial state * @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified * @param {Function} patchListener - optional function that will be called with all the patches produced here * @returns {any} a new state, or the initial state if nothing was modified */ export interface IProduce { /** Curried producer that infers the recipe from the curried output function (e.g. when passing to setState) */ <Curried>( recipe: InferRecipeFromCurried<Curried>, initialState?: InferInitialStateFromCurried<Curried> ): Curried /** Curried producer that infers curried from the recipe */ <Recipe extends AnyFunc>(recipe: Recipe): InferCurriedFromRecipe< Recipe, false > /** Curried producer that infers curried from the State generic, which is explicitly passed in. */ <State>( recipe: ( state: Draft<State>, initialState: State ) => ValidRecipeReturnType<State> ): (state?: State) => State <State, Args extends any[]>( recipe: ( state: Draft<State>, ...args: Args ) => ValidRecipeReturnType<State>, initialState: State ): (state?: State, ...args: Args) => State <State>(recipe: (state: Draft<State>) => ValidRecipeReturnType<State>): ( state: State ) => State <State, Args extends any[]>( recipe: (state: Draft<State>, ...args: Args) => ValidRecipeReturnType<State> ): (state: State, ...args: Args) => State /** Curried producer with initial state, infers recipe from initial state */ <State, Recipe extends Function>( recipe: Recipe, initialState: State ): InferCurriedFromInitialStateAndRecipe<State, Recipe, false> /** Normal producer */ <Base, D = Draft<Base>>( // By using a default inferred D, rather than Draft<Base> in the recipe, we can override it. base: Base, recipe: (draft: D) => ValidRecipeReturnType<D>, listener?: PatchListener ): Base /** Promisified dormal producer */ <Base, D = Draft<Base>>( base: Base, recipe: (draft: D) => Promise<ValidRecipeReturnType<D>>, listener?: PatchListener ): Promise<Base> } /** * Like `produce`, but instead of just returning the new state, * a tuple is returned with [nextState, patches, inversePatches] * * Like produce, this function supports currying */ export interface IProduceWithPatches { // Types copied from IProduce, wrapped with PatchesTuple <Recipe extends AnyFunc>(recipe: Recipe): InferCurriedFromRecipe<Recipe, true> <State, Recipe extends Function>( recipe: Recipe, initialState: State ): InferCurriedFromInitialStateAndRecipe<State, Recipe, true> <Base, D = Draft<Base>>( base: Base, recipe: (draft: D) => ValidRecipeReturnType<D>, listener?: PatchListener ): PatchesTuple<Base> <Base, D = Draft<Base>>( base: Base, recipe: (draft: D) => Promise<ValidRecipeReturnType<D>>, listener?: PatchListener ): Promise<PatchesTuple<Base>> } // Fixes #507: bili doesn't export the types of this file if there is no actual source in it.. // hopefully it get's tree-shaken away for everyone :) export function never_used() {}