123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- type Tail<T extends any[]> = ((...t: T) => any) extends (
- _: any,
- ...tail: infer TT
- ) => any
- ? TT
- : []
- /** Object types that should never be mapped */
- type AtomicObject =
- | Function
- | WeakMap<any, any>
- | WeakSet<any>
- | Promise<any>
- | Date
- | RegExp
- | Boolean
- | Number
- | String
- export type Draft<T> = T extends AtomicObject
- ? T
- : T extends Map<infer K, infer V>
- ? DraftMap<K, V>
- : T extends Set<infer V>
- ? DraftSet<V>
- : T extends object
- ? {-readonly [K in keyof T]: Draft<T[K]>}
- : T
- // Inline these in ts 3.7
- interface DraftMap<K, V> extends Map<Draft<K>, Draft<V>> {}
- // Inline these in ts 3.7
- interface DraftSet<V> extends Set<Draft<V>> {}
- /** Convert a mutable type into a readonly type */
- export type Immutable<T> = T extends AtomicObject
- ? T
- : T extends Map<infer K, infer V> // Ideally, but wait for TS 3.7: ? Omit<ImmutableMap<K, V>, "set" | "delete" | "clear">
- ? ImmutableMap<K, V>
- : T extends Set<infer V> // Ideally, but wait for TS 3.7: ? Omit<ImmutableSet<V>, "add" | "delete" | "clear">
- ? ImmutableSet<V>
- : T extends object
- ? {readonly [K in keyof T]: Immutable<T[K]>}
- : T
- interface ImmutableMap<K, V> extends Map<Immutable<K>, Immutable<V>> {}
- interface ImmutableSet<V> extends Set<Immutable<V>> {}
- 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>
- /**
- * 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 */
- <
- Recipe extends (...args: any[]) => any,
- Params extends any[] = Parameters<Recipe>,
- T = Params[0]
- >(
- recipe: Recipe
- ): <Base extends Immutable<T>>(
- base: Base,
- ...rest: Tail<Params>
- ) => Produced<Base, ReturnType<Recipe>>
- // ^ by making the returned type generic, the actual type of the passed in object is preferred
- // over the type used in the recipe. However, it does have to satisfy the immutable version used in the recipe
- // Note: the type of S is the widened version of T, so it can have more props than T, but that is technically actually correct!
- /** Curried producer with initial state */
- <
- Recipe extends (...args: any[]) => any,
- Params extends any[] = Parameters<Recipe>,
- T = Params[0]
- >(
- recipe: Recipe,
- initialState: Immutable<T>
- ): <Base extends Immutable<T>>(
- base?: Base,
- ...rest: Tail<Params>
- ) => Produced<Base, ReturnType<Recipe>>
- /** Normal producer */
- <Base, D = Draft<Base>, Return = void>(
- base: Base,
- recipe: (draft: D) => Return,
- listener?: PatchListener
- ): Produced<Base, Return>
- }
- export const produce: IProduce
- export default produce
- /**
- * 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 {
- /** Curried producer */
- <
- Recipe extends (...args: any[]) => any,
- Params extends any[] = Parameters<Recipe>,
- T = Params[0]
- >(
- recipe: Recipe
- ): <Base extends Immutable<T>>(
- base: Base,
- ...rest: Tail<Params>
- ) => [Produced<Base, ReturnType<Recipe>>, Patch[], Patch[]]
- // ^ by making the returned type generic, the actual type of the passed in object is preferred
- // over the type used in the recipe. However, it does have to satisfy the immutable version used in the recipe
- // Note: the type of S is the widened version of T, so it can have more props than T, but that is technically actually correct!
- /** Curried producer with initial state */
- <
- Recipe extends (...args: any[]) => any,
- Params extends any[] = Parameters<Recipe>,
- T = Params[0]
- >(
- recipe: Recipe,
- initialState: Immutable<T>
- ): <Base extends Immutable<T>>(
- base?: Base,
- ...rest: Tail<Params>
- ) => [Produced<Base, ReturnType<Recipe>>, Patch[], Patch[]]
- /** Normal producer */
- <Base, D = Draft<Base>, Return = void>(
- base: Base,
- recipe: (draft: D) => Return
- ): [Produced<Base, Return>, Patch[], Patch[]]
- }
- export const produceWithPatches: IProduceWithPatches
- /** Use a class type for `nothing` so its type is unique */
- declare class Nothing {
- // This lets us do `Exclude<T, Nothing>`
- private _: any
- }
- /**
- * The sentinel value returned by producers to replace the draft with undefined.
- */
- export const nothing: Nothing
- /**
- * To let Immer treat your class instances as plain immutable objects
- * (albeit with a custom prototype), you must define either an instance property
- * or a static property on each of your custom classes.
- *
- * Otherwise, your class instance will never be drafted, which means it won't be
- * safe to mutate in a produce callback.
- */
- export const immerable: unique symbol
- /**
- * Pass true to automatically freeze all copies created by Immer.
- *
- * By default, auto-freezing is disabled in production.
- */
- export function setAutoFreeze(autoFreeze: boolean): void
- /**
- * Pass true to use the ES2015 `Proxy` class when creating drafts, which is
- * always faster than using ES5 proxies.
- *
- * By default, feature detection is used, so calling this is rarely necessary.
- */
- export function setUseProxies(useProxies: boolean): void
- /**
- * Apply an array of Immer patches to the first argument.
- *
- * This function is a producer, which means copy-on-write is in effect.
- */
- export function applyPatches<S>(base: S, patches: Patch[]): S
- /**
- * Create an Immer draft from the given base state, which may be a draft itself.
- * The draft can be modified until you finalize it with the `finishDraft` function.
- */
- export function createDraft<T>(base: T): Draft<T>
- /**
- * Finalize an Immer draft from a `createDraft` call, returning the base state
- * (if no changes were made) or a modified copy. The draft must *not* be
- * mutated afterwards.
- *
- * Pass a function as the 2nd argument to generate Immer patches based on the
- * changes that were made.
- */
- export function finishDraft<T>(draft: T, listener?: PatchListener): Immutable<T>
- /** Get the underlying object that is represented by the given draft */
- export function original<T>(value: T): T | void
- /** Takes a snapshot of the current state of a draft and finalizes it (but without freezing). This is a great utility to print the current state during debugging (no Proxies in the way). The output of current can also be safely leaked outside the producer. */
- export function current<T>(value: T): T
- /** Returns true if the given value is an Immer draft */
- export function isDraft(value: any): boolean
- /** Returns true if the given value can be drafted by Immer */
- export function isDraftable(value: any): boolean
- export class Immer {
- constructor(config: {
- useProxies?: boolean
- autoFreeze?: boolean
- onAssign?: (
- state: ImmerState,
- prop: string | number,
- value: unknown
- ) => void
- onDelete?: (state: ImmerState, prop: string | number) => void
- onCopy?: (state: ImmerState) => void
- })
- /**
- * 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
- */
- produce: IProduce
- /**
- * When true, `produce` will freeze the copies it creates.
- */
- readonly autoFreeze: boolean
- /**
- * When true, drafts are ES2015 proxies.
- */
- readonly useProxies: boolean
- /**
- * Pass true to automatically freeze all copies created by Immer.
- *
- * By default, auto-freezing is disabled in production.
- */
- setAutoFreeze(autoFreeze: boolean): void
- /**
- * Pass true to use the ES2015 `Proxy` class when creating drafts, which is
- * always faster than using ES5 proxies.
- *
- * By default, feature detection is used, so calling this is rarely necessary.
- */
- setUseProxies(useProxies: boolean): void
- }
- export interface ImmerState<T = any> {
- parent?: ImmerState
- base: T
- copy: T
- assigned: {[prop: string]: boolean; [index: number]: boolean}
- }
- // Backward compatibility with --target es5
- declare global {
- interface Set<T> {}
- interface Map<K, V> {}
- interface WeakSet<T> {}
- interface WeakMap<K extends object, V> {}
- }
- export declare function enableAllPlugins(): void
- export declare function enableES5(): void
- export declare function enableMapSet(): void
- export declare function enablePatches(): void
|