Skip to content

Instantly share code, notes, and snippets.

@norskeld
Last active March 21, 2024 23:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save norskeld/f59eb5a2ee1bde9b7047a9d4bb1af08a to your computer and use it in GitHub Desktop.
Save norskeld/f59eb5a2ee1bde9b7047a9d4bb1af08a to your computer and use it in GitHub Desktop.
(De)serializing sets, maps and dates using replacer/reviver (TypeScript)
const enum Mark {
Set = '@set',
Map = '@map',
Date = '@date'
}
type Serialized<M extends Mark, S = unknown> = [mark: M, value: S]
type Codec<T, S> = {
serialize(value: T): Serialized<Mark, S>
deserialize(value: S): T
}
const SetCodec: Codec<Set<unknown>, unknown[]> = {
serialize: (value) => [Mark.Set, [...value]],
deserialize: (values) => new Set(values)
}
const MapCodec: Codec<Map<string, unknown>, [string, unknown][]> = {
serialize: (value) => [Mark.Map, [...value.entries()]],
deserialize: (values) => new Map(values)
}
const DateCodec: Codec<Date, string> = {
serialize: (value) => [Mark.Date, value.toISOString()],
deserialize: (value) => new Date(value)
}
const isSet = (value: unknown): value is Serialized<Mark.Set, unknown[]> =>
Array.isArray(value) && value[0] === Mark.Set
const isMap = (value: unknown): value is Serialized<Mark.Map, [string, unknown][]> =>
Array.isArray(value) && value[0] === Mark.Map
const isDate = (value: unknown): value is Serialized<Mark.Date, string> =>
Array.isArray(value) && value[0] === Mark.Date
function serialize(value: unknown): string {
return JSON.stringify(value, function (this: any, key: string, value: unknown) {
if (value instanceof Set) return SetCodec.serialize(value)
if (value instanceof Map) return MapCodec.serialize(value)
if (this[key] instanceof Date) return DateCodec.serialize(this[key])
return value
})
}
function deserialize<T = unknown>(value: string): T {
return JSON.parse(value, function (this: any, key: string, value: unknown) {
const raw = this[key] as unknown
if (isSet(raw)) return SetCodec.deserialize(raw[1])
if (isMap(raw)) return MapCodec.deserialize(raw[1])
if (isDate(raw)) return DateCodec.deserialize(raw[1])
return value
}) as T
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment