From c6cd6327525886e38f4f34e716555f295a864f0e Mon Sep 17 00:00:00 2001 From: aleclarson Date: Sat, 2 Feb 2019 11:33:47 -0500 Subject: [PATCH] types: async produce --- __tests__/produce.ts | 47 +++++++++++++++++++++++++++++++++++++++----- src/immer.d.ts | 16 +++++++-------- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/__tests__/produce.ts b/__tests__/produce.ts index 41cdfcd3..4b31cdb3 100644 --- a/__tests__/produce.ts +++ b/__tests__/produce.ts @@ -196,15 +196,52 @@ it("does not enforce immutability at the type level", () => { exactType(result, {} as any[]) }) -it("can produce nothing", () => { - let result = produce({}, _ => nothing) +it("can produce an undefined value", () => { + let base = {} as {readonly a: number} + + // Return only nothing. + let result = produce(base, _ => nothing) exactType(result, undefined) + + // Return maybe nothing. + let result2 = produce(base, draft => { + if (draft.a > 0) return nothing + }) + exactType(result2, {} as typeof base | undefined) +}) + +it("can return the draft itself", () => { + let base = {} as {readonly a: number} + let result = produce(base, draft => draft) + + // Currently, the `readonly` modifier is lost. + exactType(result, {} as {a: number} | undefined) +}) + +it("can return a promise", () => { + let base = {} as {readonly a: number} + + // Return a promise only. + exactType( + produce(base, draft => { + return Promise.resolve(draft.a > 0 ? null : undefined) + }), + {} as Promise<{readonly a: number} | null> + ) + + // Return a promise or undefined. + exactType( + produce(base, draft => { + if (draft.a > 0) return Promise.resolve() + }), + {} as (Promise<{readonly a: number}> | {readonly a: number}) + ) }) it("works with `void` hack", () => { - let obj = {} as {readonly a: number} - let res = produce(obj, s => void s.a++) - exactType(res, obj) + let base = {} as {readonly a: number} + let copy = produce(base, s => void s.a++) + exactType(copy, base) }) it("works with generic parameters", () => { diff --git a/src/immer.d.ts b/src/immer.d.ts index c7baa150..c5bee92d 100644 --- a/src/immer.d.ts +++ b/src/immer.d.ts @@ -43,17 +43,15 @@ export interface Patch { export type PatchListener = (patches: Patch[], inversePatches: Patch[]) => void -type IsVoidLike = T extends void | undefined ? 1 : 0 - /** Converts `nothing` into `undefined` */ -type FromNothing = Nothing extends T ? Exclude | undefined : T +type FromNothing = T extends Nothing ? undefined : T /** The inferred return type of `produce` */ -export type Produced = IsVoidLike extends 0 - ? FromNothing - : IsVoidLike extends 1 - ? T - : T | FromNothing> +export type Produced = Return extends void + ? Base + : Return extends Promise + ? Promise> + : FromNothing type ImmutableTuple> = { readonly [P in keyof T]: Immutable @@ -168,7 +166,7 @@ export function createDraft(base: T): Draft * Pass a function as the 2nd argument to generate Immer patches based on the * changes that were made. */ -export function finishDraft(base: Draft, listener?: PatchListener): T +export function finishDraft(draft: T, listener?: PatchListener): Immutable /** Get the underlying object that is represented by the given draft */ export function original(value: T): T | void