Describe the bug
The evaluate method in form-core, which does deep equality checking, does not work for Temporals. Previously, it always treated two Temporal instances (e.g., two Temporal.PlainDate) as equal, because they have no enumerable properties. With the recent fix #2140, it will now always treat temporal instances as not equal.
The new behavior is clearly better, but it's still incorrect. A date field backed by a Temporal instance will be considered "dirty" even if the user resets it back to the original date.
evaluate already special-cases some built-in types, like Date. With Temporal advancing to Stage 4 and shipping in browsers, it might make sense to special-case them as well.
OTOH, given that people will be using polyfills for a while yet, it may be best to duck-type. Here's one snippet that could be added to evaluate:
const objAToStringTag = objA[Symbol.toStringTag];
if (objAToStringTag.startsWith('Temporal.') && objAToStringTag === objB[Symbol.toStringTag]) {
// Handle Temporal types (they all have .equals())
return objA.equals(objB);
}
Your minimal, reproducible example
https://stackblitz.com/edit/vitejs-vite-1zaxj72u?file=src%2Fmain.ts
Steps to reproduce
The simple repro is:
evaluate(Temporal.PlainDate.from('2026-01-01'), Temporal.PlainDate.from('2026-01-01')) === false
I think any form that has a field with a Temporal value (e.g., a Temporal.PlainDate instance) will be subject to dirty-checking issues because of this.
Expected behavior
evaluate(Temporal.PlainDate.from('2026-01-01'), Temporal.PlainDate.from('2026-01-01')) === true
How often does this bug happen?
None
Screenshots or Videos
No response
Platform
This should be universal!
TanStack Form adapter
None
TanStack Form version
1.32.1
TypeScript version
No response
Additional context
Currently we are using this patch (pnpm patch) of @tanstack/form-core. It's a bit more general, and a bit less safe, because it just checks for the .equals() method. But it has the benefit of working for other types, like Decimal.js.
diff --git a/dist/cjs/utils.cjs b/dist/cjs/utils.cjs
--- a/dist/cjs/utils.cjs
+++ b/dist/cjs/utils.cjs
@@ -198,6 +198,10 @@ function evaluate(objA, objB) {
if (objA instanceof Date && objB instanceof Date) {
return objA.getTime() === objB.getTime();
}
+ // Handle Temporal types (they all have .equals())
+ if (typeof objA.equals === "function" && objA.constructor === objB.constructor) {
+ return objA.equals(objB);
+ }
if (objA instanceof Map && objB instanceof Map) {
if (objA.size !== objB.size) return false;
for (const [k, v] of objA) {
diff --git a/dist/esm/utils.js b/dist/esm/utils.js
--- a/dist/esm/utils.js
+++ b/dist/esm/utils.js
@@ -196,6 +196,10 @@ function evaluate(objA, objB) {
if (objA instanceof Date && objB instanceof Date) {
return objA.getTime() === objB.getTime();
}
+ // Handle Temporal types (they all have .equals())
+ if (typeof objA.equals === "function" && objA.constructor === objB.constructor) {
+ return objA.equals(objB);
+ }
if (objA instanceof Map && objB instanceof Map) {
if (objA.size !== objB.size) return false;
for (const [k, v] of objA) {
I wish JavaScript had a convention like for a method that checks value equality, like Symbol.for('valueEquals') or something
Describe the bug
The
evaluatemethod in form-core, which does deep equality checking, does not work for Temporals. Previously, it always treated two Temporal instances (e.g., twoTemporal.PlainDate) as equal, because they have no enumerable properties. With the recent fix #2140, it will now always treat temporal instances as not equal.The new behavior is clearly better, but it's still incorrect. A date field backed by a Temporal instance will be considered "dirty" even if the user resets it back to the original date.
evaluatealready special-cases some built-in types, likeDate. With Temporal advancing to Stage 4 and shipping in browsers, it might make sense to special-case them as well.OTOH, given that people will be using polyfills for a while yet, it may be best to duck-type. Here's one snippet that could be added to
evaluate:Your minimal, reproducible example
https://stackblitz.com/edit/vitejs-vite-1zaxj72u?file=src%2Fmain.ts
Steps to reproduce
The simple repro is:
I think any form that has a field with a Temporal value (e.g., a
Temporal.PlainDateinstance) will be subject to dirty-checking issues because of this.Expected behavior
How often does this bug happen?
None
Screenshots or Videos
No response
Platform
This should be universal!
TanStack Form adapter
None
TanStack Form version
1.32.1
TypeScript version
No response
Additional context
Currently we are using this patch (
pnpm patch) of@tanstack/form-core. It's a bit more general, and a bit less safe, because it just checks for the.equals()method. But it has the benefit of working for other types, likeDecimal.js.I wish JavaScript had a convention like for a method that checks value equality, like
Symbol.for('valueEquals')or something