Skip to content

Parsers

Parsers are functions that accepts an unknown argument and returns a discriminated union, which is either a success or a failure:

ts
type Parser<T> = (data) => ParseResult<T>

where ParseResult is a discriminated union:

ts
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:

ts
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:

ts
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:

ts
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 (===):

ts
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:

ts
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:

ts
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 with undefined
  • nullable—for unions with null
ts
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:

ts
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:

ts
const parseUser = object({
  id: parseNumber,
  name: parseString,
})
parseUser({ id: 42, name: 'Alice' }) // -> ParseSuccess

You can nest objects:

ts
const parseUser = object({
  id: parseNumber,
  name: parseString,
  address: object({
    country: parseString,
    city: parseString,
    streetAddress: parseString,
    zipCode: parseNumber,
  }),
})

You can declare optional properties:

ts
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:

ts
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:

ts
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:

ts
// Validator<number[]>
const parseNumberArray = arrays<number>(parseNumber)

Tagged/Discriminated Unions

Parse discriminated unions with unions of objects with a common tag property:

ts
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