Skip to content

Commit bf2d154

Browse files
authored
fix: update current and original typings to assert draft value is unwrapped (#1236)
1 parent 7390d6c commit bf2d154

4 files changed

Lines changed: 32 additions & 6 deletions

File tree

__tests__/type-external.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {isType, JSONArray, JSONObject, JSONTypes} from "type-plus"
22
import {Draft} from "../src/types/types-external"
3+
import {createDraft, current, original} from "../src/immer"
34

45
describe("Draft<T>", () => {
56
test("can use JSONTypes as T", () => {
@@ -17,3 +18,27 @@ describe("Draft<T>", () => {
1718
isType.equal<true, [string, number, JSONArray, JSONObject], A>()
1819
})
1920
})
21+
22+
describe("current() typings", () => {
23+
test("returns non-draft type from a draft input", () => {
24+
type Base = Readonly<{a: boolean}>
25+
const base: Base = {a: true}
26+
const draft = createDraft<Base>(base)
27+
const result = current(draft)
28+
29+
// Readonly base ensures Draft<Base> differs, exposing current()'s typing.
30+
isType.equal<true, Base, typeof result>()
31+
})
32+
})
33+
34+
describe("original() typings", () => {
35+
test("returns non-draft type from a draft input", () => {
36+
type Base = Readonly<{a: boolean}>
37+
const base: Base = {a: true}
38+
const draft = createDraft<Base>(base)
39+
const result = original(draft)
40+
41+
// Readonly base ensures Draft<Base> differs, exposing original()'s typing.
42+
isType.equal<true, Base, typeof result>()
43+
})
44+
})

src/core/current.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
die,
3+
Draft,
34
isDraft,
45
shallowCopy,
56
each,
@@ -11,8 +12,8 @@ import {
1112
} from "../internal"
1213

1314
/** 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. */
14-
export function current<T>(value: T): T
15-
export function current(value: any): any {
15+
export function current<T>(value: Draft<T>): T
16+
export function current(value: Draft<any>): any {
1617
if (!isDraft(value)) die(10, value)
1718
return currentImpl(value)
1819
}

src/core/immerClass.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export class Immer implements ProducersFns {
151151

152152
createDraft<T extends Objectish>(base: T): Draft<T> {
153153
if (!isDraftable(base)) die(8)
154-
if (isDraft(base)) base = current(base)
154+
if (isDraft(base)) base = current(base as Draft<T>)
155155
const scope = enterScope(this)
156156
const proxy = createProxy(scope, base, undefined)
157157
proxy[DRAFT_STATE].isManual_ = true

src/utils/common.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
DRAFT_STATE,
33
DRAFTABLE,
44
Objectish,
5-
Drafted,
5+
Draft,
66
AnyObject,
77
AnyMap,
88
AnySet,
@@ -66,8 +66,8 @@ export function isPlainObject(value: any): boolean {
6666

6767
/** Get the underlying object that is represented by the given draft */
6868
/*#__PURE__*/
69-
export function original<T>(value: T): T | undefined
70-
export function original(value: Drafted<any>): any {
69+
export function original<T>(value: Draft<T>): T
70+
export function original(value: Draft<any>): any {
7171
if (!isDraft(value)) die(15, value)
7272
return value[DRAFT_STATE].base_
7373
}

0 commit comments

Comments
 (0)