Hacker News new | ask | show | jobs
by perfmode 94 days ago
This is a real pain point and I run into the same tension in systems where data crosses serialization boundaries constantly. The prototype-stripping problem you're describing with JSON.parse/stringify is a specific case of a more general issue: rich domain objects don't survive wire transfer without a reconstitution step.

That said, I think the Temporal team made the right call here. Date-time logic is one of those domains where the "bag of data plus free functions" approach leads to subtle bugs because callers forget to pass the right context (calendar system, timezone) to the right function. Binding the operations to the object means the type system can enforce that a PlainDate never accidentally gets treated as a ZonedDateTime. date-fns is great but it can't give you that.

The serialization issue is solvable at the boundary. If you're using tRPC or similar, a thin transform layer that calls Temporal.Whatever.from() on the way in and .toString() on the way out is pretty minimal overhead. Same pattern people use with Decimal types or any value object that doesn't roundtrip through JSON natively. Annoying, sure, but the alternative is giving up the type safety that makes the API worth having in the first place.

3 comments

Sounds like we need an extended JSON with the express intent of conveying common extended values and rich objects: DateTime instants (with calendar system & timezone), Decimal, BigInt, etc.
I disagree: this is not unlike including the schema in the JSON itself. This should be handled by the apps themselves, since they would have to know what the keys mean regardless.

If you do want the interchange format to be the one deserializing into specific runtime data structures, use YAML. YAML's tag syntax allows you to run arbitrary code inside YAML, which can be used for what you want.

I'm not talking about something arbitrarily extensible or compound values like vectors or lat/lon. Just a few more common data types -- primitive-like values that frequently need to be passed around.

This would probably best exist as a well-known wrapper around JSON itself.

there are a zillion of these "json pro" kind of things: superjson, devalue, capnweb, all with slightly different ideas about how to lower high-level semantics to json's available types. it's so easy to do this kind of thing, its a real https://xkcd.com/927/ situation.

CBOR (Concise Binary Object Representation) has JSON-like semantics with type extension support; with built in type extensions its much easier to get some agreement about registering certain magic type IDs to mean certain things. for example from a random google search for "cbor datetime" https://j-richter.github.io/CBOR/date.html; there's an IANA registry of type IDs: https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml

however, it is binary.

Amazon ION is kind of this?

Few people seem to use it outside of Amazon tho

I think a more practical and compatible approach is to keep json as it is, and use a side channel (e.g. an openapi spec) to convey metadata. Then it is up to the client to decide that a date returned as a string is a date or string, or to create a specific class instead of a generic object
For most situations, I deal with this by keeping dates as strings throughout the app, not objects. They get read from the db as strings, passed around as strings. If I need datetime calculations, I use the language's datetime objects to do it and convert right back to string. Display formatting for users happens at the last moment, in the template.

No-one seems to like this style, but I find it much simpler than converting on db read/write and passing datetime objects around.

It's not that much about type safety. Since TypeScript uses duck typing, a DateTime could not be used as a ZonedDateTime because it'd lack the "timezone" property. The other way around, though, it would work. But I wouldn't even mind that, honestly.

The real drawback of the functional approach is UX, because it's harder to code and you don't get nice auto-complete.

But I'd easily pay that price.