diff --git a/.changeset/shiny-phones-stick.md b/.changeset/shiny-phones-stick.md new file mode 100644 index 000000000..33e6c3988 --- /dev/null +++ b/.changeset/shiny-phones-stick.md @@ -0,0 +1,5 @@ +--- +"@tanstack/db": patch +--- + +mark item drafts as a `mutable` type diff --git a/packages/db/src/collection.ts b/packages/db/src/collection.ts index eea7905cd..131698ee3 100644 --- a/packages/db/src/collection.ts +++ b/packages/db/src/collection.ts @@ -58,6 +58,7 @@ import type { Transaction as TransactionType, TransactionWithMutations, UtilsRecord, + WritableDeep, } from "./types" import type { IndexOptions } from "./indexes/index-options.js" import type { BaseIndex, IndexResolver } from "./indexes/base-index.js" @@ -1810,32 +1811,34 @@ export class CollectionImpl< // Overload 1: Update multiple items with a callback update( key: Array, - callback: (drafts: Array) => void + callback: (drafts: Array>) => void ): TransactionType // Overload 2: Update multiple items with config and a callback update( keys: Array, config: OperationConfig, - callback: (drafts: Array) => void + callback: (drafts: Array>) => void ): TransactionType // Overload 3: Update a single item with a callback update( id: TKey | unknown, - callback: (draft: TItem) => void + callback: (draft: WritableDeep) => void ): TransactionType // Overload 4: Update a single item with config and a callback update( id: TKey | unknown, config: OperationConfig, - callback: (draft: TItem) => void + callback: (draft: WritableDeep) => void ): TransactionType update( keys: (TKey | unknown) | Array, - configOrCallback: ((draft: TItem | Array) => void) | OperationConfig, + configOrCallback: + | ((draft: WritableDeep | Array>) => void) + | OperationConfig, maybeCallback?: (draft: TItem | Array) => void ) { if (typeof keys === `undefined`) { diff --git a/packages/db/src/types.ts b/packages/db/src/types.ts index 28b25e0ef..3c9da85f8 100644 --- a/packages/db/src/types.ts +++ b/packages/db/src/types.ts @@ -628,3 +628,77 @@ export type ChangeListener< T extends object = Record, TKey extends string | number = string | number, > = (changes: Array>) => void + +// Adapted from https://github.com/sindresorhus/type-fest +// MIT License Copyright (c) Sindre Sorhus + +type BuiltIns = + | null + | undefined + | string + | number + | boolean + | symbol + | bigint + | void + | Date + | RegExp + +type HasMultipleCallSignatures< + T extends (...arguments_: Array) => unknown, +> = T extends { + (...arguments_: infer A): unknown + (...arguments_: infer B): unknown +} + ? B extends A + ? A extends B + ? false + : true + : true + : false + +type WritableMapDeep> = + MapType extends ReadonlyMap + ? Map, WritableDeep> + : MapType + +type WritableSetDeep> = + SetType extends ReadonlySet + ? Set> + : SetType + +type WritableObjectDeep = { + -readonly [KeyType in keyof ObjectType]: WritableDeep +} + +type WritableArrayDeep> = + ArrayType extends readonly [] + ? [] + : ArrayType extends readonly [...infer U, infer V] + ? [...WritableArrayDeep, WritableDeep] + : ArrayType extends readonly [infer U, ...infer V] + ? [WritableDeep, ...WritableArrayDeep] + : ArrayType extends ReadonlyArray + ? Array> + : ArrayType extends Array + ? Array> + : ArrayType + +export type WritableDeep = T extends BuiltIns + ? T + : T extends (...arguments_: Array) => unknown + ? {} extends WritableObjectDeep + ? T + : HasMultipleCallSignatures extends true + ? T + : ((...arguments_: Parameters) => ReturnType) & + WritableObjectDeep + : T extends ReadonlyMap + ? WritableMapDeep + : T extends ReadonlySet + ? WritableSetDeep + : T extends ReadonlyArray + ? WritableArrayDeep + : T extends object + ? WritableObjectDeep + : unknown