Skip to content

Commit

Permalink
fix(ts): improve IProduce
Browse files Browse the repository at this point in the history
Fixes #205
  • Loading branch information
aleclarson committed Dec 15, 2018
1 parent d4d3182 commit a8f49ff
Showing 1 changed file with 26 additions and 76 deletions.
102 changes: 26 additions & 76 deletions src/immer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ type AtomicObject =
/** Use type inference to know when an array is finite */
type IsFinite<T extends any[]> = T extends never[]
? true
: T extends ReadonlyArray<infer U> ? (U[] extends T ? false : true) : true
: T extends ReadonlyArray<infer U>
? (U[] extends T ? false : true)
: true

export type DraftObject<T> = T extends object
? T extends AtomicObject ? T : {-readonly [P in keyof T]: Draft<T[P]>}
? T extends AtomicObject
? T
: {-readonly [P in keyof T]: Draft<T[P]>}
: T

export type DraftArray<T> = Array<
Expand All @@ -32,10 +36,14 @@ export type DraftTuple<T extends any[]> = {
}

export type Draft<T> = T extends any[]
? IsFinite<T> extends true ? DraftTuple<T> : DraftArray<T[number]>
? IsFinite<T> extends true
? DraftTuple<T>
: DraftArray<T[number]>
: T extends ReadonlyArray<any>
? DraftArray<T[number]>
: T extends object ? DraftObject<T> : T
? DraftArray<T[number]>
: T extends object
? DraftObject<T>
: T

export interface Patch {
op: "replace" | "remove" | "add"
Expand All @@ -59,84 +67,26 @@ export interface IProduce {
* @param initialState - if a curried function is created and this argument was given, it will be used as fallback if the curried function is called with a state of undefined
* @returns The next state: a new state, or the current state if nothing was modified
*/
<S = any>(
<S = any, R = never>(
currentState: S,
recipe: (this: Draft<S>, draftState: Draft<S>) => void | S,
recipe: (this: Draft<S>, draftState: Draft<S>) => void | R,
listener?: PatchListener
): S
): R

// curried invocations with default initial state
// 0 additional arguments
<S = any>(
recipe: (this: Draft<S>, draftState: Draft<S>) => void | S,
initialState: S
): (currentState: S | undefined) => S
// 1 additional argument of type A
<S = any, A = any>(
recipe: (this: Draft<S>, draftState: Draft<S>, a: A) => void | S,
initialState: S
): (currentState: S | undefined, a: A) => S
// 2 additional arguments of types A and B
<S = any, A = any, B = any>(
recipe: (this: Draft<S>, draftState: Draft<S>, a: A, b: B) => void | S,
initialState: S
): (currentState: S | undefined, a: A, b: B) => S
// 3 additional arguments of types A, B and C
<S = any, A = any, B = any, C = any>(
recipe: (
this: Draft<S>,
draftState: Draft<S>,
a: A,
b: B,
c: C
) => void | S,
/** Curried producer with an initial state */
<S = any, R = never>(
recipe: (this: Draft<S>, draftState: Draft<S>) => void | R,
initialState: S
): (currentState: S | undefined, a: A, b: B, c: C) => S
// any number of additional arguments, but with loss of type safety
// this may be alleviated if "variadic kinds" makes it into Typescript:
// https://github.com/Microsoft/TypeScript/issues/5453
<S = any>(
recipe: (
this: Draft<S>,
draftState: Draft<S>,
...extraArgs: any[]
) => void | S,
initialState: S
): (currentState: S | undefined, ...extraArgs: any[]) => S

// curried invocations without default initial state
// 0 additional arguments
<S = any>(recipe: (this: Draft<S>, draftState: Draft<S>) => void | S): (
currentState: S
) => S
// 1 additional argument of type A
<S = any, A = any>(
recipe: (this: Draft<S>, draftState: Draft<S>, a: A) => void | S
): (currentState: S, a: A) => S
// 2 additional arguments of types A and B
<S = any, A = any, B = any>(
recipe: (this: Draft<S>, draftState: Draft<S>, a: A, b: B) => void | S
): (currentState: S, a: A, b: B) => S
// 3 additional arguments of types A, B and C
<S = any, A = any, B = any, C = any>(
recipe: (
this: Draft<S>,
draftState: Draft<S>,
a: A,
b: B,
c: C
) => void | S
): (currentState: S, a: A, b: B, c: C) => S
// any number of additional arguments, but with loss of type safety
// this may be alleviated if "variadic kinds" makes it into Typescript:
// https://github.com/Microsoft/TypeScript/issues/5453
<S = any>(
): (currentState: S | undefined) => R

/** Curried producer with no initial state */
<S = any, R = never, Args extends any[] = any[]>(
recipe: (
this: Draft<S>,
draftState: Draft<S>,
...extraArgs: any[]
) => void | S
): (currentState: S, ...extraArgs: any[]) => S
...extraArgs: Args
) => void | R
): (currentState: S, ...extraArgs: Args) => R
}

export const produce: IProduce
Expand Down

0 comments on commit a8f49ff

Please sign in to comment.