Parsers
Parsers are functions that accepts an unknown
argument and returns a discriminated union, which is either a success or a failure:
type Parser<T> = (data) => ParseResult<T>
where ParseResult
is a discriminated union:
type ParseResult<T> =
| { tag: 'success'; value: T }
| { tag: 'failure'; error: string }
To find out whether the parsing was successful, read the tag
property of the result; for example:
import { parseString, parseNumber, object } from 'pure-parse'
import data from 'my-data.json'
const parseUser = object({
name: parseString,
age: parseNumber,
})
const result = parseUser(data)
switch (result.tag) {
case 'success':
console.log(`The user's name is "${result.value.name}"`)
break
case 'failure':
console.log(`Failed to parse the user: ${result.error}`)
break
}
TIP
For a full reference, see the API documentation on parsers.
Overview
PureParse exports two categories of functions related to parsing:
First, there are parsers; each primitive value has a corresponding parser, where the most useful ones are:
Secondly, there is a category of higher order functions that constructs new parsers based on parameters:
By composing these higher order functions and primitives, you end up with a schema-like syntax that models your data:
import { object, parseString, parseNumber, optional } from 'pure-parse'
const isUsers = arrays(
object({
id: parseNumber,
parentId: nullable(parseNumber),
name: parseString,
address: optional(
object({
country: parseString,
city: parseString,
streetAddress: parseString,
zipCode: parseNumber,
}),
),
}),
)
TIP
See the API Reference documentation for a complete inventory.
Primitives
Primitive types represent primitive values, which are immutable and have no properties:
parseString('hello') // -> ParseSuccess
parseNumber(42) // -> ParseSuccess
parseBoolean(true) // -> ParseSuccess
parseNull(null) // -> ParseSuccess
parseUndefined(undefined) // -> ParseSuccess
parseBigInt(42n) // -> ParseSuccess
parseSymbol(Symbol()) // -> ParseSuccess
Equality Checks for Primitive Literals
Primitive literals such as true
, false
, 42
, "hello"
, and null
are all types and values (depending on the context they appear in). Use the equalsGuard()
function to create a guard function that compares the data with the strict equality operator (===
):
const parseRed = equals('red')
parseRed('red') // -> ParseSuccess<'red'>
parseRed('blue') // -> ParseError
const parseOne = equals(1)
parseOne(1) // -> ParseSuccess<1>
parseOne(2) // -> ParseError
When called with multiple arguments, equals()
validates a union:
const parseDirection = equals('north', 'south', 'east', 'west')
parseDirection('north') // -> ParseSuccess<'north' | 'south' | 'east' | 'west'>
parseDirection('up') // -> ParseError
const parseDigit = equals(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
parseDigit(5) // -> ParseSuccess<0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9>
parseDigit(50) // -> ParseError
Unions
Unions types—or sum types—represent values that can be one of several types. Use the oneOf()
function to create a validation function for a union type:
const parseStringOrNumber = oneOf(parseString, parseNumber)
parseStringOrNumber('hello') // -> ParseSuccess
parseStringOrNumber(123) // -> ParseSuccess
Since it is very common to create unions with null
and undefined
, there are two helper functions for validating optional and nullable types:
undefineable
—for unions withundefined
nullable
—for unions withnull
const parseUndefineableString = undefineable(parseString)
parseOptionalString('hello') // -> ParseSuccess
parseOptionalString(undefined) // -> ParseSuccess
const parseNullableString = optional(parseString)
parseNullableString('hello') // -> ParseSuccess
parseNullableString(null) // -> ParseSuccess
Tuples
Tuples are arrays of fixed length, where each element has a specific type. Use the tuple()
function to create a parser function for a tuple type:
import { tupleGuard as tuple } from 'pure-parse'
const parseCoordinate = tuple([parseNumber, parseNumber])
parseCoordinate([42, 34]) // -> ParseSuccess
const parseTransparentColor = tuple([parseString, parseNumber])
parseTransparentColor(['#FF0000', 0.5]) // -> ParseSuccess
Objects
Parse objects with the object()
function which takes an object with keys and corresponding validation functions:
const parseUser = object({
id: parseNumber,
name: parseString,
})
parseUser({ id: 42, name: 'Alice' }) // -> ParseSuccess
You can nest objects:
const parseUser = object({
id: parseNumber,
name: parseString,
address: object({
country: parseString,
city: parseString,
streetAddress: parseString,
zipCode: parseNumber,
}),
})
You can declare optional properties:
const parseUser = object({
id: parseNumber,
name: optional(parseString),
})
parseUser({ id: 42 }) // -> ParseSuccess
parseUser({ id: 42, name: undefined }) // -> ParseSuccess
parseUser({ id: 42, name: 'Jiří' }) // -> ParseSuccess
You can explicitly declare the type of the object and annotate the validation function with the type as a type parameter:
type User = {
id: number
name?: string
}
const parseUser = object<User>({
id: parseNumber,
name: optional(parseString),
})
Arrays
Arrays are ordered set of elements of the same type. Use the arrays()
function to create a validation function for an arrays type:
const parseBase = equals('A', 'T', 'C', 'G')
const parseDna = arrays(parseBase)
parseDna(['A', 'T', 'A', 'T', 'C', 'G']) // -> ParseSuccess
When explicitly declaring arrays types, provide type of the item in the arrays type argument:
// Validator<number[]>
const parseNumberArray = arrays<number>(parseNumber)
Tagged/Discriminated Unions
Parse discriminated unions with unions of objects with a common tag property:
const parseState = oneOf(
object({
tag: equals('loading'),
}),
object({
tag: equals('error'),
error: parseString,
}),
object({
tag: equals('loaded'),
message: parseString,
}),
)
parseState({ tag: 'loading' }) // -> ParseSuccess
parseState({ tag: 'error', error: 'Failed to load' }) // -> ParseSuccess
parseState({ tag: 'loaded', message: 'Data loaded' }) // -> ParseSuccess