io-ts-types

repository·master·Indexed 43 days ago

https://github.com/gcanti/io-ts-types

A collection of runtime types and combinators designed to extend the functionality of the io-ts library. Version 0.5.19 provides specialized codecs for handling BigInts, booleans, dates, JSON strings, and Either types, as well as utilities like fromNewtype, fromNullable, and lens generation via getLenses.

Tokens
18.7K
Snippets
77
Records
84
Agent score
54%

What's inside io-ts-types

  1. Understand the NonEmptyString type and branding

    master

    To use NonEmptyString effectively in TypeScript, understand the following related types:

    • NonEmptyString: A type alias representing a branded string. It is defined as t.Branded<string, NonEmptyStringBrand>. This allows you to use the type in function signatures to guarantee that the input has passed the NonEmptyString codec.
    • NonEmptyStringBrand: An interface used for the unique symbol branding to prevent accidental assignment of regular strings to NonEmptyString types.
    • NonEmptyStringC: The interface for the codec itself, extending t.Type<NonEmptyString, string, unknown>.
  2. Install io-ts-types via npm

    master

    To install the stable version of io-ts-types, use npm.

    Important: Starting from version 0.5.0, io-ts-types lists fp-ts, io-ts, newtype-ts, and monocle-ts as peerDependencies. This means you must manually install these packages in your project to ensure compatibility.

    npm i io-ts-types
  3. Use io-ts-types combinators and types

    master

    The io-ts-types library provides a collection of runtime types and combinators designed to work with io-ts. You can import various specialized codecs for handling common data formats (like strings, numbers, dates, and JSON) and utility combinators to transform or refine your existing io-ts codecs.

    Available categories of exports include:

    • String Parsing: BooleanFromString, IntFromString, NumberFromString, BigIntFromString, JsonFromString, NonEmptyString.
    • Date Handling: DateFromISOString, DateFromNumber, DateFromUnixTime, and general date codecs.
    • Collections: nonEmptyArray, readonlyNonEmptyArray, setFromArray, readonlySetFromArray, mapFromEntries, readonlyMapFromEntries.
    • Nullability & Options: fromNullable, optionFromNullable, option.
    • Combinators & Utilities: withMessage, withValidate, withEncode, mapOutput, withFallback, fromRefinement, fromNewtype, clone, either, getLenses.
    • Specialized Types: UUID, regexp.
  4. Use the `either` codec to deserialize Either types

    master

    The either function creates a codec for an Either<L, R> type. It takes two codecs (one for the Left side and one for the Right side) and returns an EitherC codec. This codec is designed to deserialize the JSON representation of an Either structure, where the structure is tagged with _tag: 'Left' or _tag: 'Right'.

    import { either } from 'io-ts-types/lib/either'
    import { left, right } from 'fp-ts/lib/Either'
    import * as t from 'io-ts'
    import { PathReporter } from 'io-ts/lib/PathReporter'
    
    const T = either(t.string, t.number)
    
    // Decoding a Right value
    assert.deepStrictEqual(T.decode(right(1)), right(right(1)))
    
    // Decoding a Left value
    assert.deepStrictEqual(T.decode(left('a')), right(left('a')))
    
    // Handling invalid data
    const invalidResult = T.decode(right('a'))
    console.log(PathReporter.report(invalidResult))
    // Output: ['Invalid value "a" supplied to : Either<string, number>/1: Right<string>/right: number']
  5. Use the option codec to handle Option types

    master

    The option function creates a codec that represents an Option<A> type. It is designed to deserialize JSON representations of an Option (using fp-ts style none and some structures).

    When you pass a codec C to option(C), it returns an OptionC<C> which is a t.Type that validates whether a value is either none or some(value) where value matches the underlying codec.

    import { option } from 'io-ts-types/lib/option'
    import { right } from 'fp-ts/lib/Either'
    import { none, some } from 'fp-ts/lib/Option'
    import * as t from 'io-ts'
    import { PathReporter } from 'io-ts/lib/PathReporter'
    
    const T = option(t.number)
    
    // Validates 'none'
    assert.deepStrictEqual(T.decode(none), right(none))
    
    // Validates 'some(1)'
    assert.deepStrictEqual(T.decode(some(1)), right(some(1)))
    
    // Reports error for invalid types inside 'some'
    assert.deepStrictEqual(PathReporter.report(T.decode(some('a'))), [
      'Invalid value "a" supplied to : Option<number>/1: Some<number>/value: number'
    ])
  6. Use mapFromEntries to decode Maps from entry arrays

    master

    The mapFromEntries function creates a codec that transforms an array of key-value pairs (entries) into a JavaScript Map. This is useful when your input data is an array like [[key1, value1], [key2, value2]] but you want to work with a Map object in your application.

    To use it, you must provide:

    1. A codec for the keys (keyCodec).
    2. An Ord instance for the keys to allow proper sorting/ordering during decoding.
    3. A codec for the values (valueCodec).
    4. (Optional) A custom name for the codec.
    // Example usage (requires io-ts and an Ord implementation)
    import * as t from 'io-ts';
    import { mapFromEntries } from 'io-ts-types';
    import { stringOrd } from 'io-ts-types/ord'; // Assuming an Ord provider exists
    
    const MapCodec = mapFromEntries(
      t.string,
      stringOrd,
      t.number
    );
    
    // Decodes: [['a', 1], ['b', 2]] -> Map { 'a' => 1, 'b' => 2 }
    const result = MapCodec.decode([['a', 1], ['b', 2]]);
  7. Use readonlySetFromArray to validate ReadonlySet from an Array

    master

    The readonlySetFromArray function creates an io-ts codec that validates an input ReadonlyArray and transforms it into a ReadonlySet. This is useful when you receive data as an array (e.g., from JSON) but want to treat it as a unique set of values in your application logic.

    To use it, you must provide:

    1. A codec C for the elements in the set.
    2. An Ord (ordering) function for the type of the elements, which is required for the set's internal logic.
    3. An optional name for the codec.

    Note: This feature was added in v0.5.7.

    // Example usage (requires io-ts and an Ord implementation)
    import * as t from 'io-ts';
    import { readonlySetFromArray } from 'io-ts-types';
    import { Ord } from './your-ord-implementation'; // You must provide an Ord for the type
    
    const stringOrd: Ord<string> = { ... };
    const codec = readonlySetFromArray(t.string, stringOrd);
    
    // Validates a ReadonlyArray and returns a ReadonlySet
    const result = codec.decode(['a', 'b', 'a']);
  8. Use BooleanFromString to decode boolean strings

    master

    The BooleanFromString codec allows you to decode string values into boolean types. It specifically recognizes the strings 'true' and 'false'. Any other string value will result in a decoding error.

    import { BooleanFromString } from 'io-ts-types/lib/BooleanFromString'
    import { right } from 'fp-ts/lib/Either'
    import { PathReporter } from 'io-ts/lib/PathReporter'
    
    // Successful decodes
    assert.deepStrictEqual(BooleanFromString.decode('true'), right(true))
    assert.deepStrictEqual(BooleanFromString.decode('false'), right(false))
    
    // Failed decode
    assert.deepStrictEqual(PathReporter.report(BooleanFromString.decode('a')), [
      'Invalid value "a" supplied to : BooleanFromString'
    ])
  9. Use withMessage to customize error messages

    master

    The withMessage function returns a clone of a given io-ts codec that uses a custom string as the error message when decoding fails. This is useful for providing more human-readable or context-specific error messages in PathReporter outputs.

    Signature: withMessage<C extends t.Any>(codec: C, message: (i: t.InputOf<C>, c: t.Context) => string): C

    Parameters:

    • codec: The original io-ts codec you want to wrap.
    • message: A function that receives the input (i) and the context (c) and returns the error message string.
    import { withMessage } from 'io-ts-types/lib/withMessage'
    import * as t from 'io-ts'
    import { PathReporter } from 'io-ts/lib/PathReporter'
    import { right } from 'fp-ts/lib/Either'
    
    const T = withMessage(t.number, () => 'Invalid number')
    
    assert.deepStrictEqual(T.decode(1), right(1))
    assert.deepStrictEqual(PathReporter.report(T.decode(null)), ['Invalid number'])
  10. Use withFallback to provide a default value on codec failure

    master

    The withFallback function returns a clone of a given codec that succeeds using a provided fallback value a if the original codec fails to decode the input. This is useful for ensuring a type remains valid even when the input data does not match the expected schema.

    Signature: withFallback<C extends t.Any>(codec: C, a: t.TypeOf<C>, name?: string): C

    • codec: The original io-ts codec to attempt decoding.
    • a: The fallback value of type t.TypeOf<C> to use if decoding fails.
    • name (optional): A custom name for the resulting codec. Defaults to `withFallback(${codec.name})`.
    import { withFallback } from 'io-ts-types/lib/withFallback'
    import * as t from 'io-ts'
    import { right } from 'fp-ts/lib/Either'
    
    // If decoding a number fails, return -1 instead
    const T = withFallback(t.number, -1)
    
    // Succeeds with the original value
    assert.deepStrictEqual(T.decode(1), right(1))
    
    // Fails to decode 'a' as a number, so returns the fallback -1
    assert.deepStrictEqual(T.decode('a'), right(-1))
  11. Use getLenses to create lenses for codec properties

    master

    The getLenses function generates a mapping of Lens objects for every property defined in an io-ts codec. For a given codec C, it returns an object where each key corresponds to a property name in the decoded type, and the value is a Lens that allows you to focus on and manipulate that specific property.

    getLenses accepts a codec that satisfies the HasLenses constraint (which includes t.InterfaceType or ExactHasLenses).

    import * as t from 'io-ts'
    import { getLenses } from 'io-ts-types/lib/getLenses'
    
    const Person = t.type({
      name: t.string,
      age: t.number
    })
    
    const lenses = getLenses(Person)
    // lenses.name is a Lens<Person, string>
    // lenses.age is a Lens<Person, number>
    
    assert.strictEqual(lenses.age.get({ name: 'Giulio', age: 44 }), 44)
  12. Use the UUID type and codec

    master

    The UUID module provides a branded type and a codec for validating Universally Unique Identifiers (UUIDs). It uses io-ts branding to ensure that a string is not just any string, but specifically a validated UUID at the type level.

    • UUIDBrand: An interface used for branding.
    • UUID: A type alias representing a branded string (t.Branded<string, UUIDBrand>).
    • UUID (codec): A codec of type t.BrandC<t.StringC, UUIDBrand> used for runtime decoding and validation.
    import { UUID } from 'io-ts-types/lib/UUID'
    import { right } from 'fp-ts/lib/Either'
    import { PathReporter } from 'io-ts/lib/PathReporter'
    
    // Valid UUID
    assert.deepStrictEqual(
      UUID.decode('00000000-0000-0000-0000-000000000000'),
      right('00000000-0000-0000-0000-000000000000')
    )
    
    // Invalid UUID
    assert.deepStrictEqual(PathReporter.report(UUID.decode('not a uuid')), [
      'Invalid value "not a uuid" supplied to : UUID'
    ])