diff --git a/.changeset/fix-temporal-isplainobject.md b/.changeset/fix-temporal-isplainobject.md new file mode 100644 index 000000000..19f2f12f6 --- /dev/null +++ b/.changeset/fix-temporal-isplainobject.md @@ -0,0 +1,11 @@ +--- +'@tanstack/db': patch +--- + +fix(db): treat objects with `Symbol.toStringTag` as leaf values in `IsPlainObject` + +Temporal types (e.g. `Temporal.PlainDate`, `Temporal.ZonedDateTime`) have `Symbol.toStringTag` set to a string. Previously, `IsPlainObject` would return `true` for these types because they are objects and not in the `JsBuiltIns` union. This caused the `Ref` mapped type to recursively walk Temporal methods, mangling them to `{}`. + +The fix adds a `T extends { readonly [Symbol.toStringTag]: string }` check before returning `true`, causing all class instances with `Symbol.toStringTag` (Temporal types, etc.) to be treated as leaf values with their types fully preserved. + +Fixes #1372 diff --git a/packages/db/src/query/builder/types.ts b/packages/db/src/query/builder/types.ts index 6dce531f8..476438c13 100644 --- a/packages/db/src/query/builder/types.ts +++ b/packages/db/src/query/builder/types.ts @@ -862,6 +862,12 @@ export type Prettify = { /** * IsPlainObject - Utility type to check if T is a plain object + * + * Returns `false` for: + * - Arrays (ReadonlyArray) + * - JavaScript built-ins (Date, Map, Set, etc.) + * - Objects with `Symbol.toStringTag` (class instances like Temporal types, + * TypedArrays not already in JsBuiltIns, etc.) — these are not plain data objects */ type IsPlainObject = T extends unknown ? T extends object @@ -869,7 +875,9 @@ type IsPlainObject = T extends unknown ? false : T extends JsBuiltIns ? false - : true + : T extends { readonly [Symbol.toStringTag]: string } + ? false + : true : false : false