npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@flix-tech/fp-ts-type-check

v0.2.2

Published

Type validation in runtime

Downloads

434

Readme

fp-ts-type-check is a library for runtime type validation of variables where you can't say their type for sure i.e. data you get via some API. It's somewhat similar to Typescript's Type Guards except it uses type system to make sure this data is properly validated.

Features:

  • Type safe. Typescript compiler makes sure your types and your type checkers are always in sync.
  • Detailed error reports. If parsing of a big deep-nested structure failed - you'll know where exactly in that structure you have invalid data and why it was considered invalid
  • Composable. Type checkers for big structures are created by composing checkers for simple structures.
  • Functional. Each type checker is a pure function returning Either type from fp-ts. It's up for you to decide how to handle errors.
  • Tree-shakeable. Bundle only functions you really use.

Installation

To install the stable version:

npm install '@flix-tech/fp-ts-type-check@~0.2.0'

While the major version number is 0 changes in minor version number bay break backward compatibility so you should stick to a fixed minor version.

Usage

Meet Parser[T], the main type of this library. Parser[T] is a function that takes any variable and checks if it's a variable of type T. It either returns the same value as T or ParseError object with parse error details. Parser's type definition looks somewhat like this:

type Parser<A> = (x: unknown): Either<ParseError, A>;

interface ParseError {
  path: string; // Path to the property causing error in deep nested structures
  message: string; // Parsing error message
}

We're using the type Either from fp-ts library.

Parsers for some complex structures you'd want to validate are composed from small parsers like here:

import * as P from 'fp-ts-type-check';

interface ShoppingListItem {
  name: string;
  amount: { count: number; unit?: string };
}
const shoppingListItemParser: P.Parser<ShoppingListItem> = P.type({
  name: P.string,
  amount: P.type({
    count: P.number,
    unit: P.optional(P.string),
  }),
});

shoppingListItem({name: "Apple", amount: {count: 5}}); // Right<ShoppingListItem>({name: "Apple", amount: {count: 5}})

shoppingListItem({name: "Apple", amount: {count: "some"}}); // Left<ParseError>({path: ".amount.count", message: "expected number, got string"})

As you can see, ParseError data is for your eyes only, user should get a generalized error message appropriate in this case.

You can reuse your parsers to construct parsers for even bigger structures:

type ShoppingList = array<ShoppingListItem>;

const shoppingListParser: P.Parser<ShoppingList> = P.arrayOf(shoppingListItemParser);

const validShoppingList = [
  {name: "Apple", amount: {count: 5}},
  {name: "Milk", amount: {count: 500, unit: 'ml'}},
];
shoppingListParser(validShoppingList); // Right<ShoppingList>(...)

const invalidShoppingList = [
  {name: "Apple", amount: {count: 5}},
  {name: "Milk", amount: {unit: 'ml'}}, // No count here
];
shoppingListParser(invalidShoppingList); // Left<ParseError>({path: "[1].amount.count", message: "expected number, got undefined"})

API documentation

Simple type parsers

  • string(): Parser<string> - checks that value is string.
  • boolean(): Parser<boolean> - checks that value is boolean.
  • number(): Parser<number> - checks that value is number.
  • object(): Parser<object> - checks that value is any object.
  • any(): Parser<any> - does not check anything.
  • exact<A>(expected: A): Parser<A> - checks that value is same as expected one.
  • oneOf<A>(allowed: A[]): Parser<A> - checks that value is one of allowed ones.
  • keyOf<A extends object>(allowed: A): Parser<keyof A> - checks that value is string and also is a key of object allowed.

Copositional parsers

  • type<A>(propertyParsers: { [K in keyof A]: Parser<A[K]> }): Parser<A> - checks that values is an object and validates each it's property with corresponding parser.

  • arrayOf<A>(parseBody: Parser<A>): Parser<A[]> - checks that value is an array and every item matches parseBody parser.

  • optional<A>(parseBody: Parser<A>): Parser<A | undefined> - checks that value is either undefined or matches parseBody parser.

  • nullable<A>(parseBody: Parser<A>): Parser<A | null> - checks that value is either null or matches parseBody parser.

  • discriminatedUnion<A extends {type: string;}>(parsers: {(type value): (type parser)}): Parser<A> - checks that value is a discriminated union with discriminant in type property. Example usage:

    type Foo = { type: 'foo'; foo: number };
    type Bar = { type: 'bar'; bar: number };
    type FooBar = Foo | Bar;
      
    const parser: P.Parser<FooBar> = P.discriminatedUnion({
      foo: P.type({ foo: P.number }),
      bar: P.type({ bar: P.number }),
    });

Logic combination parsers

  • and(parserA: Parser<A>, parserB<B>): Parser<A & B> - checks that value matches both types A and B.
  • or(parserA: Parser<A>, parserB<B>): Parser<A | B> - checks that value matches any of types A or B.

License

The MIT License (MIT)