Skip to content

Data Types ​

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
ts
isString('hello') // -> true
isNumber(42) // -> true
isBoolean(true) // -> true
isNull(null) // -> true
isUndefined(undefined) // -> true
isBigInt(42n) // -> true
isSymbol(Symbol()) // -> true

Primitive Literals (equals) ​

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
ts
const isRed = equalsGuard('red')
isRed('red') // -> true
isRed('blue') // -> false

const isOne = equalsGuard(1)
isOne(1) // -> true
isOne(2) // -> false

To validate a union of literals, use oneOf:

ts
const parseDirection = oneOf(
  equals('north'),
  equals('south'),
  equals('east'),
  equals('west'),
)
parseDirection('north') // -> ParseSuccess<'north' | 'south' | 'east' | 'west'>
parseDirection('up') // -> ParseError

const parseDigit = oneOf(
  equals(0),
  equals(1),
  equals(2),
  equals(3),
  equals(4),
  equals(5),
  equals(6),
  equals(7),
  equals(8),
  equals(9),
)
parseDigit(5) // -> ParseSuccess<0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9>
parseDigit(50) // -> ParseError
ts
const isDirection = oneOfGuard(
  equals('north'),
  equals('south'),
  equals('east'),
  equals('west'),
)
isDirection('north') // -> true
isDirection('east') // -> true

const isDigit = oneOfGuard(
  equalsGuard(0),
  equalsGuard(1),
  equalsGuard(2),
  equalsGuard(3),
  equalsGuard(4),
  equalsGuard(5),
  equalsGuard(6),
  equalsGuard(7),
  equalsGuard(8),
  equalsGuard(9),
)
isDigit(5) // -> true
isDigit(100) // -> false

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
ts
const isStringOrNumber = unionGuard(isString, isNumber)
isStringOrNumber('hello') // -> true
isStringOrNumber(123) // -> true

Since it is very common to create unions with null and undefined, there are two helper functions for validating optional and nullable types:

ts
const parseUndefineableString = undefineable(parseString)
parseOptionalString('hello') // -> ParseSuccess<string | undefined>
parseOptionalString(undefined) // -> ParseSuccess<string | undefined>

const parseNullableString = optional(parseString)
parseNullableString('hello') // -> ParseSuccess<string | null>
parseNullableString(null) // -> ParseSuccess<string | null>
ts
const isUndefineableString = undefineableGuard(isString)
isOptionalString('hello') // -> true
isOptionalString(undefined) // -> true

const isNullableString = optionalGuard(isString)
isNullableString('hello') // -> true
isNullableString(null) // -> true

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
ts
const isCoordinate = tupleGuard([isNumber, isNumber])
isCoordinate([42, 34]) // -> true

const isTransparentColor = tupleGuard([isString, isNumber])
isTransparentColor(['#FF0000', 0.5]) // -> true

Objects ​

Validate objects with object/objectGuard which takes an object as argument, with keys and corresponding validation functions:

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

You can nest objects:

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

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
ts
const isUser = objectGuard({
  id: isNumber,
  name: optionalGuard(isString),
})
isUser({ id: 42 }) // -> true
isUser({ id: 42, name: undefined }) // -> true
isUser({ id: 42, name: 'Jiří' }) // -> true

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),
})
ts
type User = {
  id: number
  name?: string
}
const isUser = objectGuard<User>({
  id: isNumber,
  name: optionalGuard(isString),
})

Arrays ​

Use array/arrayGuard to validate arrays:

ts
const parseBase = oneOf(equals('A'), equals('T'), equals('C'), equals('G'))
const parseDna = array(parseBase)
parseDna(['A', 'T', 'A', 'T', 'C', 'G']) // -> ParseSuccess
ts
const isBase = oneOf(
  equalsGuard('A'),
  equalsGuard('T'),
  equalsGuard('C'),
  equalsGuard('G'),
)
const isDna = arrayGuard(isBase)
isDna(['A', 'T', 'A', 'T', 'C', 'G']) // -> true

When explicitly declaring array types, provide type of the item in the array type argument:

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

Tagged/Discriminated Unions ​

Validate discriminated unions by combining oneOf with object:

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
ts
const isState = unionGuard(
  objectGuard({
    tag: equalsGuard('loading'),
  }),
  objectGuard({
    tag: equalsGuard('error'),
    error: isString,
  }),
  objectGuard({
    tag: equalsGuard('loaded'),
    message: isString,
  }),
)

isState({ tag: 'loading' }) // -> true
isState({ tag: 'error', error: 'Failed to load' }) // -> true
isState({ tag: 'loaded', message: 'Data loaded' }) // -> true