Skip to content

Commit 09c7afc

Browse files
fix(db): treat objects with Symbol.toStringTag as leaf values in IsPlainObject (#1373)
* fix(db): treat objects with Symbol.toStringTag as leaf values in IsPlainObject Temporal types (Temporal.PlainDate, ZonedDateTime, etc.) have Symbol.toStringTag set but are not in the JsBuiltIns union, causing IsPlainObject to return true and Ref<T> to recursively walk their methods and mangle them to {}. Adds a Symbol.toStringTag check so all class instances (including all Temporal types) are treated as leaf values, preserving their types in query select projections. Fixes #1372 * ci: apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent eed43cd commit 09c7afc

2 files changed

Lines changed: 20 additions & 1 deletion

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@tanstack/db': patch
3+
---
4+
5+
fix(db): treat objects with `Symbol.toStringTag` as leaf values in `IsPlainObject`
6+
7+
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<T>` mapped type to recursively walk Temporal methods, mangling them to `{}`.
8+
9+
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.
10+
11+
Fixes #1372

packages/db/src/query/builder/types.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -909,14 +909,22 @@ export type Prettify<T> = {
909909

910910
/**
911911
* IsPlainObject - Utility type to check if T is a plain object
912+
*
913+
* Returns `false` for:
914+
* - Arrays (ReadonlyArray)
915+
* - JavaScript built-ins (Date, Map, Set, etc.)
916+
* - Objects with `Symbol.toStringTag` (class instances like Temporal types,
917+
* TypedArrays not already in JsBuiltIns, etc.) — these are not plain data objects
912918
*/
913919
type IsPlainObject<T> = T extends unknown
914920
? T extends object
915921
? T extends ReadonlyArray<any>
916922
? false
917923
: T extends JsBuiltIns
918924
? false
919-
: true
925+
: T extends { readonly [Symbol.toStringTag]: string }
926+
? false
927+
: true
920928
: false
921929
: false
922930

0 commit comments

Comments
 (0)