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 | 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 = // 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> | IfAvailable> export type WritableDraft = {-readonly [K in keyof T]: Draft} export type Draft = T extends PrimitiveType ? T : T extends AtomicObject ? T : T extends IfAvailable> // Map extends ReadonlyMap ? Map, Draft> : T extends IfAvailable> // Set extends ReadonlySet ? Set> : T extends WeakReferences ? T : T extends object ? WritableDraft : T /** Convert a mutable type into a readonly type */ export type Immutable = T extends PrimitiveType ? T : T extends AtomicObject ? T : T extends IfAvailable> // Map extends ReadonlyMap ? ReadonlyMap, Immutable> : T extends IfAvailable> // Set extends ReadonlySet ? ReadonlySet> : T extends WeakReferences ? T : T extends object ? {readonly [K in keyof T]: Immutable} : 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 extends Nothing ? undefined : T /** The inferred return type of `produce` */ export type Produced = Return extends void ? Base : Return extends Promise ? Promise> : FromNothing /** * Utility types */ type PatchesTuple = readonly [T, Patch[], Patch[]] type ValidRecipeReturnType = | State | void | undefined | (State extends undefined ? Nothing : never) type ValidRecipeReturnTypePossiblyPromise = | ValidRecipeReturnType | Promise> type PromisifyReturnIfNeeded< State, Recipe extends AnyFunc, UsePatches extends boolean > = ReturnType extends Promise ? Promise : State> : UsePatches extends true ? PatchesTuple : State /** * Core Producer inference */ type InferRecipeFromCurried = Curried extends ( base: infer State, ...rest: infer Args ) => any // extra assertion to make sure this is a proper curried function (state, args) => state ? ReturnType extends State ? ( draft: Draft, ...rest: Args ) => ValidRecipeReturnType> : never : never type InferInitialStateFromCurried = 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 extends ValidRecipeReturnTypePossiblyPromise ? ( base: Immutable, ...args: RestArgs ) => PromisifyReturnIfNeeded // 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, ...rest: infer RestArgs ) => ValidRecipeReturnTypePossiblyPromise ? ( base?: State | undefined, ...args: RestArgs ) => PromisifyReturnIfNeeded : 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) */ ( recipe: InferRecipeFromCurried, initialState?: InferInitialStateFromCurried ): Curried /** Curried producer that infers curried from the recipe */ (recipe: Recipe): InferCurriedFromRecipe< Recipe, false > /** Curried producer that infers curried from the State generic, which is explicitly passed in. */ ( recipe: ( state: Draft, initialState: State ) => ValidRecipeReturnType ): (state?: State) => State ( recipe: ( state: Draft, ...args: Args ) => ValidRecipeReturnType, initialState: State ): (state?: State, ...args: Args) => State (recipe: (state: Draft) => ValidRecipeReturnType): ( state: State ) => State ( recipe: (state: Draft, ...args: Args) => ValidRecipeReturnType ): (state: State, ...args: Args) => State /** Curried producer with initial state, infers recipe from initial state */ ( recipe: Recipe, initialState: State ): InferCurriedFromInitialStateAndRecipe /** Normal producer */ >( // By using a default inferred D, rather than Draft in the recipe, we can override it. base: Base, recipe: (draft: D) => ValidRecipeReturnType, listener?: PatchListener ): Base /** Promisified dormal producer */ >( base: Base, recipe: (draft: D) => Promise>, listener?: PatchListener ): Promise } /** * 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: Recipe): InferCurriedFromRecipe ( recipe: Recipe, initialState: State ): InferCurriedFromInitialStateAndRecipe >( base: Base, recipe: (draft: D) => ValidRecipeReturnType, listener?: PatchListener ): PatchesTuple >( base: Base, recipe: (draft: D) => Promise>, listener?: PatchListener ): Promise> } // 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() {}