Why coercion
And why coercion instead of codec or serializer/deserializer like io-ts (❤️) or @sinclair/typebox?
TL;DR – Because of Standard Schema
To me, Standard Schema is an excellent initiative and has great adoption. Building anything StandardSchema-compliant opens the door to tRPC, ts-rest and a ton of others tools.
From my point of view, the trade-off is acceptable and I am OK delegating serializing to clumsy APIs like JSON.stringify(data, replacer)
and parsing to JSON.parse(jsonAsText, reviver)
.
See MDN for documentation of JSON.stringify
's replacer and JSON.parse
's reviver.
Example with JSON.stringify/parse
ts
import { x } from 'unhoax'
const itemQuantitySchema = x.number.refine('Quantity', (value) => value > 0)
const itemNameSchema = x.string
const shoppingListSchema = x.object({
name: x.string,
items: x.mapOf(itemNameSchema, itemQuantitySchema),
})
const shoppingListData = {
name: 'Groceries',
items: new Map([
['Apple', 5],
['Carrot', 8],
]),
}
const brokenJson = JSON.stringify(shoppingListData)
// '{ "name":"Groceries", "items": {} }' <-- not items in there !
const json = JSON.stringify(shoppingListData, (key, value) => {
if (value instanceof Map) return [...value.entries()]
return value
})
// '{ "name": "Groceries", "items": [["Apple", 5], ["Carrot", 8]] }'
const parsedJson = JSON.parse(json)
const shoppingList2 = shoppingListSchema.parse(parsedJson)
// No need to provide a `reviver`, the `x.mapOf` schema can
// parse entries directly. We only need the `replacer` to
// serialize a Map as JSON.