sinclairzx81 / typebox

Json Schema Type Builder with Static Type Resolution for TypeScript
Other
4.79k stars 153 forks source link

[BUG] Value.create caches the default date #743

Closed itsyoboieltr closed 7 months ago

itsyoboieltr commented 7 months ago

I made a simple reproduction to demonstrate my issue:

This works as expected:

import { Type as t, type DateOptions } from '@sinclair/typebox';
import { Create } from '@sinclair/typebox/value';

/** `[JavaScript]` Creates a DateTime type */
export const DateTime = (options?: DateOptions) => t.Date({ ...options });

export const reproductionSchema = t.Object({ date: DateTime() });

const test = Create(reproductionSchema);
console.log(test);
// output: { date: 2024-01-23T20:02:00.000Z }
setTimeout(() => {
  const test2 = Create(reproductionSchema);
  console.log(test2);
  // output: { date: 2024-01-23T20:03:00.000Z }
}, 60000);

This does not work: the data console.logged is always the same

import { Type as t, type DateOptions } from '@sinclair/typebox';
import { Create } from '@sinclair/typebox/value';

/** `[JavaScript]` Creates a DateTime type */
export const DateTime = (options?: DateOptions) =>
  t.Date({ default: new Date(new Date().setSeconds(0, 0)), ...options });

export const reproductionSchema = t.Object({ date: DateTime() });

const test = Create(reproductionSchema);
console.log(test);
// output: { date: 2024-01-23T20:02:00.000Z }
setTimeout(() => {
  const test2 = Create(reproductionSchema);
  console.log(test2);
  // output: { date: 2024-01-23T20:02:00.000Z }
}, 60000);

It feels like the result of the default value is somehow cached? It would be nice if it could be rerun for each Value.Create, the current implementation feels a bit unintuitive for me, I totally expected it to be called again.

sinclairzx81 commented 7 months ago

@itsyoboieltr Hi,

This isn't a bug, but it is a somewhat annoying constraint TB places upon itself.

It can be worked around by converting the type into function.

import { Type as t, type DateOptions } from '@sinclair/typebox';
import { Create } from '@sinclair/typebox/value';

export const DateTime = (options?: DateOptions) =>
  t.Date({ default: new Date(), ...options });

// Convert to a function
export const reproductionSchema = () => t.Object({ date: DateTime() });

const test = Create(reproductionSchema());
console.log(test);
setTimeout(() => {
  const test2 = Create(reproductionSchema());
  console.log(test2);
}, 3000);

Hope this helps!