Skip to content

docs: name the state types that keep async results typed as the state, fix the JSON Patch note and state the TypeScript versions - #203

Merged
unadlib merged 4 commits into
mainfrom
docs/explicit-state-types-and-patch-notes
Oct 11, 2026
Merged

unadlib merged 4 commits into
mainfrom
docs/explicit-state-types-and-patch-notes

Conversation

@unadlib

@unadlib unadlib commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Part of #168.

Summary

Three documentation fixes, with no change to the code or the types.

# Topic main This PR
1 Async recipes with an explicit state type The README, the create() page and the migration guide say that an explicit state type with an async recipe gives Promise<State>. That holds for concrete state types since #201, but a type parameter, as in create<T>(base, async (draft) => { … }) in a generic function, or a state type that includes Promises, such as object or unknown, still gives the state type, as in 1.3.0, also for recipes that may return a Promise. The call returns a Promise. names these state types, and that leaving out the type argument in generic code gives Promise<T>
2 JSON Patch compatibility the README, the create() page and the Patches guide say that patches are fully compatible with JSON Patch when arrayLengthAssignment is false, although JSON Patch paths are strings both pathAsArray and arrayLengthAssignment are false, as the "JSON Patch" bullet of the Patches guide already says
3 Supported TypeScript versions not stated TypeScript 5.0 and later, the version that the package checks compile the types with

Changes, one commit per item

  1. docs: name the explicit state types that keep async results typed as the state (item 1): the paragraph on async recipes in the README and on the create() page, and the first TypeScript bullet of the migration guide in the README and on the website.
  2. docs: state that JSON Patch compatibility also needs string paths (item 2): the README, the create() page and the Patches guide.
  3. docs: state the TypeScript versions that the types support (item 3): "Using TypeScript" in the README and the TypeScript guide.

Verification

  • Item 1, with TypeScript 5.8.3 and the declarations built from main at 09ab87b; npm 1.3.0 gives the same types:

    Call Type At run time
    create<T>(base, async () => {}) in function f<T extends object>(base: T) T a Promise
    the same with a recipe typed (draft) => void | Promise<void>, or curried, create<T>(async () => {}) T, (base: T) => T a Promise, or one when the recipe returns one
    create<object>(…) or create<unknown>(…) with an async recipe or one that may return a Promise object, unknown a Promise, or one when the recipe returns one
    create(base, async (draft) => { … }) in the same generic function Promise<T> a Promise
    create(async (draft: Draft<T>) => {}) in a generic function (base: T) => Promise<T> a Promise
  • Item 3: pnpm test:package compiles a consumer of the packed package with TypeScript 5.0.4.

  • The branch merges with fix: bound the search for repeated moved array elements and type maybe-async recipes of primitive states #202, which edits nearby lines of the README, the create() page and the migration guide, without conflicts.

Not covered

  • The types themselves. TypeScript checks overloads by the subtype relation before assignability. A type parameter is assignable to the base type of the explicit-state overloads, which blocks the inference of the state type, but is no subtype of it, so the overload that infers the state type accepts the async recipe first, through its default void recipe return. An extra overload for async recipes with the same base type changed no type in the full overload set, and NoInfer needs TypeScript 5.4. Two other changes were tried on fix: bound the search for repeated moved array elements and type maybe-async recipes of primitive states #202: async overloads with a plain base type before the overloads that infer the state type fix these calls, but also changed 10 of the other 152 types that the probes check in TypeScript 5.0.4–5.9.3, such as create(state, (draft) => { draft.count++; }), typed DraftedObject<State> without strict mode, and create(0, (n) => n + 1), rejected in strict mode; giving the inferring overloads a never return by default broke five existing type checks, among them recipes typed any and generic helpers whose recipes take (draft: T) => T. So these limits are documented instead.

@github-actions

Copy link
Copy Markdown

Coverage after merging docs/explicit-state-types-and-patch-notes into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   apply.ts100%100%100%100%
   array.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   error.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

@github-actions

Copy link
Copy Markdown

Coverage after merging docs/explicit-state-types-and-patch-notes into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   apply.ts100%100%100%100%
   array.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   error.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

@unadlib
unadlib merged commit 978b917 into main Oct 11, 2026
10 checks passed
@unadlib
unadlib deleted the docs/explicit-state-types-and-patch-notes branch October 11, 2026 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant