json-bouncer
v1.2.1
Published
Type-Safe JSON Decoders for TypeScript strongly inspired by Elm
Readme
json-bouncer
Type-Safe JSON Decoders for TypeScript, strongly inspired by Elm.
If you're using TypeScript, working with JSON values can be dangerous. Naively casting the JSON value into the type that you expect it to be gives you no gurantees whatsoever that this is actually the case. You introduce an object into your statically typed code, that can be of any shape, and every piece of code that works with data from this object can crash or misbehave unexpectedly.
// No runtime validation
User user = JSON.parse(value) as User;json-bouncer provides a framework to build runtime validators that are
statically guaranteed to return a value of the correct type if they succeed.
It closely mirrors how JSON values are handled in the Elm
language with a few
useful additions that are only possible in the TypeScript type system.
This is how they look like:
interface User {
readonly id: number
readonly email: string
readonly name: string
}
const userDecoder: Decoder<User> = object({
id: field("id", number()),
email: field("email", string()),
name: field("name", string()),
})And this is how the decoder can be used:
> validUserObject = {id: 1, email: "[email protected]", name: "John Doe"}
> invalidUserObject = {id: 1, email: "[email protected]"}
> userDecoder(validUserObject)
{type: "Ok", value: {id: 1, email: "[email protected]", name: "John Doe"}}
> userDecoder(invalidUserObject)
{type: "Err", error: {...}}TypeScript statically checks that the decoder is in sync with the specified type. This would give a compile error:
interface User {
readonly id: number
readonly email: string
readonly name: string
}
const userDecoder: Decoder<User> = object({
id: field("id", number()),
emall: field("email", string()),
name: field("name", string()),
})Can you spot the mistake? This is what TypeScript says:
User.ts(7,7): error TS2322: Type 'Decoder<{ id: number; emall: string; name: string; }>' is not assignable to type 'Decoder<User>'.
Type 'Result<DecodeError, { id: number; emall: string; name: string; }>' is not assignable to type 'Result<DecodeError, User>'.
Type 'Ok<{ id: number; emall: string; name: string; }>' is not assignable to type 'Result<DecodeError, User>'.
Type 'Ok<{ id: number; emall: string; name: string; }>' is not assignable to type 'Ok<User>'.
Type '{ id: number; emall: string; name: string; }' is not assignable to type 'User'.
Property 'email' is missing in type '{ id: number; emall: string; name: string; }'.The field email was mistakenly named emall in the decoder definition.
