Skip to content

fix: type fieldUpdatedAt/fieldCreatedAt as Date in CRUD callbacks#648

Closed
MMMikeM wants to merge 2 commits into
LegendApp:mainfrom
MMMikeM:fix/synced-crud-date-field-types
Closed

fix: type fieldUpdatedAt/fieldCreatedAt as Date in CRUD callbacks#648
MMMikeM wants to merge 2 commits into
LegendApp:mainfrom
MMMikeM:fix/synced-crud-date-field-types

Conversation

@MMMikeM
Copy link
Copy Markdown

@MMMikeM MMMikeM commented Mar 28, 2026

Summary

clone() uses a JSON reviver that converts ISO 8601 strings to Date objects at runtime. When fieldUpdatedAt or fieldCreatedAt is specified in syncedCrud, the create/update/delete callback parameters receive Date values for those fields — but the TypeScript types still say string.

This PR makes the types honest by:

  • Adding FUpdatedAt/FCreatedAt string literal type params to SyncedCrudPropsBase and all syncedCrud overloads
  • Using a CrudCallbackInput utility type that remaps the specified field keys from string to Date
  • When neither field is set, types are unchanged (fully backwards compatible)

Before

syncedCrud({
    list: async () => fetchTasks(),
    create: (input) => {
        // TypeScript says input.createdAt is `string`
        // Runtime: input.createdAt is a Date object
        console.log(input.createdAt instanceof Date); // true
    },
    fieldUpdatedAt: 'updatedAt',
    fieldCreatedAt: 'createdAt',
});

After

syncedCrud({
    list: async () => fetchTasks(),
    create: (input) => {
        // TypeScript correctly says input.createdAt is `Date`
        input.createdAt.toISOString(); // ✓ no error
    },
    fieldUpdatedAt: 'updatedAt',
    fieldCreatedAt: 'createdAt',
});

Caveat

TypeScript doesn't support partial type argument inference. If the user explicitly specifies TRemote (e.g. syncedCrud<Task>({...})), FUpdatedAt/FCreatedAt fall back to undefined and the date fields stay typed as string. This only affects the explicit-generic case — the common pattern of letting TRemote be inferred from list/get works correctly.

Test plan

  • With both fieldUpdatedAt and fieldCreatedAt set: date fields typed as Date, others unchanged
  • Without either field set: all types unchanged (backwards compat)
  • With only fieldUpdatedAt: only that field becomes Date, fieldCreatedAt stays string
  • Zero new type errors introduced (all 57 existing errors are pre-existing in supabase/tanstack-query/react files)

MMMikeM added 2 commits March 28, 2026 09:56
These tests document the current type mismatch: clone() converts
ISO 8601 strings to Date at runtime, but the callback parameter
types still say string. The expectTypeOf assertions expect Date,
so these tests will show type errors until the types are fixed.
clone() uses a JSON reviver that converts ISO 8601 strings to Date
objects at runtime. The create/update/delete callback parameter types
now reflect this when fieldUpdatedAt or fieldCreatedAt is specified.

When neither field is set, types are unchanged (backwards compatible).
@MMMikeM MMMikeM force-pushed the fix/synced-crud-date-field-types branch from 38aaef2 to 11f7b4d Compare March 28, 2026 07:56
@MMMikeM MMMikeM closed this Mar 28, 2026
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