A simple and composable way to validate data in JavaScript (and TypeScript).

Overview

A simple and composable way
to validate data in JavaScript (and TypeScript).



UsageWhy?PrinciplesDemoExamplesDocumentation



Superstruct makes it easy to define interfaces and then validate JavaScript data against them. Its type annotation API was inspired by Typescript, Flow, Go, and GraphQL, giving it a familiar and easy to understand API.

But Superstruct is designed for validating data at runtime, so it throws (or returns) detailed runtime errors for you or your end users. This is especially useful in situations like accepting arbitrary input in a REST or GraphQL API. But it can even be used to validate internal data structures at runtime when needed.


Usage

Superstruct allows you to define the shape of data you want to validate:

import { assert, object, number, string, array } from 'superstruct'

const Article = object({
  id: number(),
  title: string(),
  tags: array(string()),
  author: object({
    id: number(),
  }),
})

const data = {
  id: 34,
  title: 'Hello World',
  tags: ['news', 'features'],
  author: {
    id: 1,
  },
}

assert(data, Article)
// This will throw an error when the data is invalid.
// If you'd rather not throw, you can use `is()` or `validate()`.

Superstruct ships with validators for all the common JavaScript data types, and you can define custom ones too:

import { is, define, object, string } from 'superstruct'
import isUuid from 'is-uuid'
import isEmail from 'is-email'

const Email = define('Email', isEmail)
const Uuid = define('Uuid', isUuid.v4)

const User = object({
  id: Uuid,
  email: Email,
  name: string(),
})

const data = {
  id: 'c8d63140-a1f7-45e0-bfc6-df72973fea86',
  email: '[email protected]',
  name: 'Jane',
}

if (is(data, User)) {
  // Your data is guaranteed to be valid in this block.
}

Superstruct can also handle coercion of your data before validating it, for example to mix in default values:

import { create, object, number, string, defaulted } from 'superstruct'

const User = object({
  id: defaulted(number(), () => i++),
  name: string(),
})

const data = {
  name: 'Jane',
}

// You can apply the defaults to your data while validating.
const user = create(data, User)
// {
//   id: 1,
//   name: 'Jane',
// }

And if you use TypeScript, Superstruct automatically ensures that your data has proper typings whenever you validate it:

import { is, object, number, string } from 'superstruct'

const User = object({
  id: number(),
  name: string()
})

const data: unknown = { ... }

if (is(data, User)) {
  // TypeScript knows the shape of `data` here, so it is safe to access
  // properties like `data.id` and `data.name`.
}

Superstruct supports more complex use cases too like defining arrays or nested objects, composing structs inside each other, returning errors instead of throwing them, and more! For more information read the full Documentation.


Why?

There are lots of existing validation libraries—joi, express-validator, validator.js, yup, ajv, is-my-json-valid... But they exhibit many issues that lead to your codebase becoming hard to maintain...

  • They don't expose detailed errors. Many validators simply return string-only errors or booleans without any details as to why, making it difficult to customize the errors to be helpful for end-users.

  • They make custom types hard. Many validators ship with built-in types like emails, URLs, UUIDs, etc. with no way to know what they check for, and complicated APIs for defining new types.

  • They don't encourage single sources of truth. Many existing APIs encourage re-defining custom data types over and over, with the source of truth being spread out across your entire code base.

  • They don't throw errors. Many don't actually throw the errors, forcing you to wrap everywhere. Although helpful in the days of callbacks, not using throw in modern JavaScript makes code much more complex.

  • They're tightly coupled to other concerns. Many validators are tightly coupled to Express or other frameworks, which results in one-off, confusing code that isn't reusable across your code base.

  • They use JSON Schema. Don't get me wrong, JSON Schema can be useful. But it's kind of like HATEOAS—it's usually way more complexity than you need and you aren't using any of its benefits. (Sorry, I said it.)

Of course, not every validation library suffers from all of these issues, but most of them exhibit at least one. If you've run into this problem before, you might like Superstruct.

Which brings me to how Superstruct solves these issues...


Principles

  1. Customizable types. Superstruct's power is in making it easy to define an entire set of custom data types that are specific to your application, and defined in a single place, so you have full control over your requirements.

  2. Unopinionated defaults. Superstruct ships with native JavaScript types, and everything else is customizable, so you never have to fight to override decisions made by "core" that differ from your application's needs.

  3. Composable interfaces. Superstruct interfaces are composable, so you can break down commonly-repeated pieces of data into components, and compose them to build up the more complex objects.

  4. Useful errors. The errors that Superstruct throws contain all the information you need to convert them into your own application-specific errors easy, which means more helpful errors for your end users!

  5. Familiar API. The Superstruct API was heavily inspired by Typescript, Flow, Go, and GraphQL. If you're familiar with any of those, then its schema definition API will feel very natural to use, so you can get started quickly.


Demo

Try out the live demo on JSFiddle to get an idea for how the API works, or to quickly verify your use case:

Demo screenshot.


Examples

Superstruct's API is very flexible, allowing it to be used for a variety of use cases on your servers and in the browser. Here are a few examples of common patterns...


Documentation

Read the getting started guide to familiarize yourself with how Superstruct works. After that, check out the full API reference for more detailed information about structs, types and errors...

Docs screenshot.


License

This package is MIT-licensed.

Comments
  • Discussion: Compile-Time TypeScript type validation

    Discussion: Compile-Time TypeScript type validation

    The current type definitions located at @types/superstruct are good. However, they do not check the type of your struct at compile time, leading to poorer autocomplete as the shape of your struct is not known to TypeScript. A major reason for this is TypeScript's widening of string literals in non-constant contexts. For example, the type of the following struct definition:

    const def = {
      someProp: 'number'
    }
    

    is known as:

    {someProp: string}
    

    rather than

    {someProp: 'number'}
    

    This makes it near impossible to write any kind of mapped type that would be valid to your struct. In my research, I have discovered two possible solutions rather than just defaulting to any: a shape-only type and more specific struct definitions.

    With a shape only type, upon constructing a struct with this definition:

    const definition = {
      someProp: 'number',
      someObject: {
        anotherProp: 'boolean?'
      }
    }
    

    you would receive a validation function that has the following type:

    (objectToTest: any) => {someProp: any, someObject: {anotherProp: any}}
    

    This would at least enable autocomplete with your struct's properties, preventing typos at compile time. This does not protect against a property possibly being null (for example, struct.someObject.anotherProp can be null in the above example) nor does it actually enforce the types (i.e. number) you've already defined in your struct.

    The other option is to use string literal narrowing in your struct definitions, or const enums. For example, if we define a const enum like this:

    const enum Types {
      String = 'string',
      OptionalString = 'string?'
      Number = 'number',
      OptionalNumber = 'number?'
    }
    

    it becomes possible to write a mapped type such that a struct definition such as this:

    const definition = {
      someProp: Types.Number
    }
    

    returns a struct function with the following type:

    (objectToTest: any) => {someProp: number}
    

    This also works if you force the compiler to not widen the type. The following definition will produce the same type:

    const definition = {
      someProp: 'number' as 'number'
    }
    

    The nice thing about using a const enum is that is does not force this library to switch to TypeScript, rather, the enum constants themselves are inlined upon compilation rather than using a static class.

    I'm looking here to start a discussion about how to implement such a feature in the typings, and whether any of these solutions I've thought of so far are any good.

    ♥ help please question 
    opened by charles-toller 16
  • Rework Build tools

    Rework Build tools

    Why?

    Rollup is known for consistently producing the smallest bundles. In this case, the biggest reason is because Browserify's overhead is much bigger than Rollup. Rollup also inlines its imports directly within the bundles, whereas Browserify leaves require statements, each of which needs its own interop wrapper.

    ...That's also to say that the Browserify build has to deal with require statements at runtime, which seems like a silly step to take since we're pre-compiling anyway.

    Bublé also consistently produces smaller ES5 code and with less configuration. It exposes its own buble/register which is now in the tests. Because of this, the tests' elapsed time has dropped from ~750ms to ~115ms!

    screen shot 2017-11-29 at 8 08 52 pm

    Commands

    As for the actual "build" command, I imported a builder.js file I use across a bunch of my modules. It produces 3 files in 3 different formats:

    • ES Module: lib/superstruct.es.js
    • CommonJS: lib/superstruct.js
    • UMD: lib/superstruct.min.js

    I've updated package.json's entries to expose these three correctly.

    The main benefit here is that Webpack/Rollup users get to use partial imports for free, and Node.js servers can use the CJS module (sans requires!) as normal.

    The "watch" command was updated to use Rollup directly. Nothing extra is needed. I have it producing the CJS/main file only. Don't think the others are needed here.

    Results

    The final GZIP size of the UMD file is 5.11 kB! 🎉 Of course, this number is actually smaller if you compress the other two files (no UMD header).

    Suggestions

    • It's a personal thing, I know, but the "clean" command seems useless to me. 😜

    • I'd also remove .npmignore in favor of specifying a files key within package.json. I personally only allow the lib directory -- imo, devs can lookup the repo for docs & examples. But you can definitely include docs and examples here too if you want. 😄


    Closes #12 because Rollup handles this internally.


    Sorry if this was more of an overhaul than you would have liked @ianstormtaylor 😅

    improvement 
    opened by lukeed 14
  • Rename files to `cjs.js` for compatibility with React Native

    Rename files to `cjs.js` for compatibility with React Native

    Importing @solana/web3.js in React Native throws the following error.

    error: Error: While trying to resolve module `superstruct` from file `/Users/sluscher/mobile-wallet-adapter/js/node_modules/@solana/web3.js/lib/index.browser.cjs.js`, the package `/Users/sluscher/mobile-wallet-adapter/js/node_modules/superstruct/package.json` was successfully found. However, this package itself specifies a `main` module field that could not be resolved (`/Users/sluscher/mobile-wallet-adapter/js/node_modules/superstruct/lib/index.cjs`. Indeed, none of these files exist:
    
      * /Users/sluscher/mobile-wallet-adapter/js/node_modules/superstruct/lib/index.cjs(.native|.android.js|.native.js|.js|.android.json|.native.json|.json|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx)
    

    You can see that the React Native packager expects a .js extension in addition to .cjs

    If superstruct could rename the CommonJS bundles from .cjs to .cjs.js that would make it Just Work™ for React Native folks!

    More details on the problem here, if you're interested: https://github.com/facebook/metro/issues/535

    debt 
    opened by steveluscher 13
  • React native package `main` field related error.

    React native package `main` field related error.

    Hei,

    I'm trying to plug supertruct to a react-native app, but i'm getting this error

    error: Error: While trying to resolve module `superstruct` from file `validation.js`, the package `node_modules/superstruct/package.json` was successfully found. 
    However, this package itself specifies a `main` module field that could not be resolved (`node_modules/superstruct/index.cjs`. Indeed, none of these files exist:
    
    question ⚑ needs info 
    opened by cmnstmntmn 13
  • Validating objects with unspecified properties

    Validating objects with unspecified properties

    Let's say I have a struct: struct.object({foo: 'string'})
    Then I pass an object: s.validate({ foo: 'bar', bar: 'foo' })
    Currently I am receiving an error with path [ 'bar' ] and message Expected a value of typeundefinedforbarbut received"foo".

    I think that this behavior is incorrect, and the path should be empty array, i.e. the error belongs to whole struct and not to unspecified property. And the message should be adjusted accordingly.

    The following use case illustrates why I think so. I face this situation quite often. There is a form that receives data from backend, user edits the data, then submits it back. The thing is that what backend sends, what backend expects to receive, and what the form internally uses sometimes have different shapes (the form needs some extra data to look nice, or rich text needs to be transformed from markdown to internal representation, etc...). This leads to unspecified properties, and results in validation error. UI then checks paths of errors and displays them on corresponding UI controls. Those errors with empty path array (like multi-field errors) are then displayed in an ugly red box for whole form errors. The problem with current error paths is that there is no way I can know that unspecified fields errors belong to whole form, they look like they belong to particular UI control, but there is no such control on the form.

    opened by doomsower 13
  • Expected a value of type `undefined` for `author.test` but received `undefined`

    Expected a value of type `undefined` for `author.test` but received `undefined`

    'use strict';
    const { struct } = require('../lib/superstruct/lib/index');
    const Article = struct({
      id: 'number',
      author: {
        id: 'number',
      },
    });
    const data = {
      id: 34,
      author: {
        id: 1,
        test: undefined,
      },
    };
    const article = Article(data);
    console.log('article', article);
    

    I use the struct to validate data from excel, some unsed keys are set to undefined, and I get an error like : Expected a value of type undefined for author.test but received undefined

    I try to partial, but it is not recursive. so I create this issues and a pull request.

    opened by saighost 13
  • Usage for other than types validations

    Usage for other than types validations

    Hey

    I checked the docs, but didn't find any info if this library is supposed to be used only to validate types of data or it can be used for other validations.

    For example, I can check if value is a number. Is it possible and how to check, if this value is less than 100 or more than 6?

    question 
    opened by vladshcherbin 13
  • Customize Error Paths

    Customize Error Paths

    Hi 👋 really digging this library for validating objects

    My only question is about customizing paths when creating types via superstruct

    const struct = superstruct({
      types: {
        location: value => {
          const empty = Object.keys(value).reduce((acc, key) => {
            return value[key].state === null && value[key].county === null
              ? acc.concat(key)
              : acc;
          }, []);
          const str = empty.join(", ");
          return str === ""
            ? true
            : `Either state or county for ${str} is required`;
        },
        duplicate: val => {
          const mmap = Object.keys(val).reduce((map, key) => {
            CHECK_LIST.forEach(item => {
              if (val[key][item] !== "" && val[key][item] != null) {
                map.set(`${item}.${val[key][item]}`, `${key}.${item}`);
              }
            });
            return map;
          }, new MultiMap());
          
          const gatherDuplicates = mmap
            .values()
            .reduce((acc, x) => (x.length >= 2 ? acc.concat(x) : acc), []);
            
          const error = `The following keys are duplicates: ${gatherDuplicates.join(", ")}`
    
          return gatherDuplicates.length > 0 ? error : true;
        }
      }
    });
    
    const Location = struct('location&duplicate')
    
    const data = {
      123: {
        state: null,
        county: null
      },
      456: {
        state: null,
        county: null
      }
    }
    
    Location.validate(data)
    

    Currently the above code checks if the dynamic keys have either state or county filled in and then if either state or county is a duplicate

    Returning custom messages works great but for whatever reason the paths array is always empty which brings me to my question of customizing paths because i have all of the information i need to create a path but no obvious way of doing, unless I am missing something ?

    feature ♥ help please 
    opened by davidchase 12
  • Supported node version

    Supported node version

    Which versions of node are supported? Currently due to dependencies only node 8+ is supported, is that intended?

    error [email protected]: The engine "node" is incompatible with this module. Expected version ">=8".

    bug 
    opened by pbarbiero 11
  • enums gives relaxed type

    enums gives relaxed type

    const struct = object({text: enums(["foo", "bar"])})
    const {text}  = create({ text: "foo"}, struct)
    

    the text variable is given a type of string while I am expecting "foo" | "bar". I can get around the problem with the more verbose union([literal("foo"), literal("bar")])

    bug ♥ help please 
    opened by Louis-Tian 10
  • `coerce()` should run recursively (and not assert)

    `coerce()` should run recursively (and not assert)

    Right now, it's impossible to coerce a nested structure, both because coerce() also validates (#467 ) but also because coerce() only runs on the top-level object. For instance, coerce({}, type({...props})) will fail, even if all props have coercions, because they never run.

    coerce() should function parallel to check() (preferably with a context object). In the case of validate-with-coerce, they could still run like now, in tandem.

    bug debt improvement 
    opened by mikestopcontinues 10
  • Bump eslint from 7.32.0 to 8.31.0

    Bump eslint from 7.32.0 to 8.31.0

    Bumps eslint from 7.32.0 to 8.31.0.

    Release notes

    Sourced from eslint's releases.

    v8.31.0

    Features

    • 52c7c73 feat: check assignment patterns in no-underscore-dangle (#16693) (Milos Djermanovic)
    • b401cde feat: add options to check destructuring in no-underscore-dangle (#16006) (Morten Kaltoft)
    • 30d0daf feat: group properties with values in parentheses in key-spacing (#16677) (Francesco Trotta)

    Bug Fixes

    • 35439f1 fix: correct syntax error in prefer-arrow-callback autofix (#16722) (Francesco Trotta)
    • 87b2470 fix: new instance of FlatESLint should load latest config file version (#16608) (Milos Djermanovic)

    Documentation

    • 4339dc4 docs: Update README (GitHub Actions Bot)
    • 4e4049c docs: optimize code block structure (#16669) (Sam Chen)
    • 54a7ade docs: do not escape code blocks of formatters examples (#16719) (Sam Chen)
    • e5ecfef docs: Add function call example for no-undefined (#16712) (Elliot Huffman)
    • a3262f0 docs: Add mastodon link (#16638) (Amaresh S M)
    • a14ccf9 docs: clarify files property (#16709) (Sam Chen)
    • 3b29eb1 docs: fix npm link (#16710) (Abdullah Osama)
    • a638673 docs: fix search bar focus on Esc (#16700) (Shanmughapriyan S)
    • f62b722 docs: country flag missing in windows (#16698) (Shanmughapriyan S)
    • 4d27ec6 docs: display zh-hans in the docs language switcher (#16686) (Percy Ma)
    • 8bda20e docs: remove manually maintained anchors (#16685) (Percy Ma)
    • b68440f docs: User Guide Getting Started expansion (#16596) (Ben Perlmutter)

    Chores

    • 65d4e24 chore: Upgrade @​eslint/eslintrc@​1.4.1 (#16729) (Brandon Mills)
    • 8d93081 chore: fix CI failure (#16721) (Sam Chen)
    • 8f17247 chore: Set up automatic updating of README (#16717) (Nicholas C. Zakas)
    • 4cd87cb ci: bump actions/stale from 6 to 7 (#16713) (dependabot[bot])
    • fd20c75 chore: sort package.json scripts in alphabetical order (#16705) (Darius Dzien)
    • 10a5c78 chore: update ignore patterns in eslint.config.js (#16678) (Milos Djermanovic)

    v8.30.0

    Features

    • 075ef2c feat: add suggestion for no-return-await (#16637) (Daniel Bartholomae)
    • 7190d98 feat: update globals (#16654) (Sébastien Règne)

    Bug Fixes

    • 1a327aa fix: Ensure flat config unignores work consistently like eslintrc (#16579) (Nicholas C. Zakas)
    • 9b8bb72 fix: autofix recursive functions in no-var (#16611) (Milos Djermanovic)

    Documentation

    • 6a8cd94 docs: Clarify Discord info in issue template config (#16663) (Nicholas C. Zakas)
    • ad44344 docs: CLI documentation standardization (#16563) (Ben Perlmutter)
    • 293573e docs: fix broken line numbers (#16606) (Sam Chen)
    • fa2c64b docs: use relative links for internal links (#16631) (Percy Ma)
    • 75276c9 docs: reorder options in no-unused-vars (#16625) (Milos Djermanovic)
    • 7276fe5 docs: Fix anchor in URL (#16628) (Karl Horky)
    • 6bef135 docs: don't apply layouts to html formatter example (#16591) (Tanuj Kanti)
    • dfc7ec1 docs: Formatters page updates (#16566) (Ben Perlmutter)

    ... (truncated)

    Changelog

    Sourced from eslint's changelog.

    v8.31.0 - December 31, 2022

    • 65d4e24 chore: Upgrade @​eslint/eslintrc@​1.4.1 (#16729) (Brandon Mills)
    • 35439f1 fix: correct syntax error in prefer-arrow-callback autofix (#16722) (Francesco Trotta)
    • 87b2470 fix: new instance of FlatESLint should load latest config file version (#16608) (Milos Djermanovic)
    • 8d93081 chore: fix CI failure (#16721) (Sam Chen)
    • 4339dc4 docs: Update README (GitHub Actions Bot)
    • 8f17247 chore: Set up automatic updating of README (#16717) (Nicholas C. Zakas)
    • 4e4049c docs: optimize code block structure (#16669) (Sam Chen)
    • 54a7ade docs: do not escape code blocks of formatters examples (#16719) (Sam Chen)
    • 52c7c73 feat: check assignment patterns in no-underscore-dangle (#16693) (Milos Djermanovic)
    • e5ecfef docs: Add function call example for no-undefined (#16712) (Elliot Huffman)
    • a3262f0 docs: Add mastodon link (#16638) (Amaresh S M)
    • 4cd87cb ci: bump actions/stale from 6 to 7 (#16713) (dependabot[bot])
    • a14ccf9 docs: clarify files property (#16709) (Sam Chen)
    • 3b29eb1 docs: fix npm link (#16710) (Abdullah Osama)
    • fd20c75 chore: sort package.json scripts in alphabetical order (#16705) (Darius Dzien)
    • a638673 docs: fix search bar focus on Esc (#16700) (Shanmughapriyan S)
    • f62b722 docs: country flag missing in windows (#16698) (Shanmughapriyan S)
    • 4d27ec6 docs: display zh-hans in the docs language switcher (#16686) (Percy Ma)
    • 8bda20e docs: remove manually maintained anchors (#16685) (Percy Ma)
    • b401cde feat: add options to check destructuring in no-underscore-dangle (#16006) (Morten Kaltoft)
    • b68440f docs: User Guide Getting Started expansion (#16596) (Ben Perlmutter)
    • 30d0daf feat: group properties with values in parentheses in key-spacing (#16677) (Francesco Trotta)
    • 10a5c78 chore: update ignore patterns in eslint.config.js (#16678) (Milos Djermanovic)

    v8.30.0 - December 16, 2022

    • f2c4737 chore: upgrade @​eslint/eslintrc@​1.4.0 (#16675) (Milos Djermanovic)
    • 1a327aa fix: Ensure flat config unignores work consistently like eslintrc (#16579) (Nicholas C. Zakas)
    • 075ef2c feat: add suggestion for no-return-await (#16637) (Daniel Bartholomae)
    • ba74253 chore: standardize npm script names per #14827 (#16315) (Patrick McElhaney)
    • 6a8cd94 docs: Clarify Discord info in issue template config (#16663) (Nicholas C. Zakas)
    • 0d9af4c ci: fix npm v9 problem with file: (#16664) (Milos Djermanovic)
    • 7190d98 feat: update globals (#16654) (Sébastien Règne)
    • ad44344 docs: CLI documentation standardization (#16563) (Ben Perlmutter)
    • 90c9219 refactor: migrate off deprecated function-style rules in all tests (#16618) (Bryan Mishkin)
    • 9b8bb72 fix: autofix recursive functions in no-var (#16611) (Milos Djermanovic)
    • 293573e docs: fix broken line numbers (#16606) (Sam Chen)
    • fa2c64b docs: use relative links for internal links (#16631) (Percy Ma)
    • 75276c9 docs: reorder options in no-unused-vars (#16625) (Milos Djermanovic)
    • 7276fe5 docs: Fix anchor in URL (#16628) (Karl Horky)
    • 6bef135 docs: don't apply layouts to html formatter example (#16591) (Tanuj Kanti)
    • dfc7ec1 docs: Formatters page updates (#16566) (Ben Perlmutter)
    • 8ba124c docs: update the prefer-const example (#16607) (Pavel)
    • e6cb05a docs: fix css leaking (#16603) (Sam Chen)

    v8.29.0 - December 2, 2022

    • 0311d81 docs: Configuring Plugins page intro, page tweaks, and rename (#16534) (Ben Perlmutter)

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Impossible to `Describe` generic types with conditional

    Impossible to `Describe` generic types with conditional

    I cannot figure out how to describe generics with conditionals. This might be a limitation by TypeScript though.

    Given the following types:

    enum Types {
      One = "one",
      Two = "two",
    }
    
    type Validating<T extends Types = Types> = {
      type: T;
      value: T extends Types.One ? string : never;
    };
    

    I can't figure out how to type value in Validating. This is my general idea:

    const Validating: Describe<Validating> = union([
      object({
        type: literal(Types.One),
        value: string(),
      }),
      object({
        type: literal(Types.Two),
      }),
    ]);
    
    assert({ type: Types.One, value: "Value!" }, Validating);
    assert({ type: Types.Two }, Validating);
    

    But this does not compile, giving the following error:

    Type 'Struct<{ type: Types.One; value: string; } | { type: Types.Two; }, null>' is not assignable to type 'Describe<Validating<Types>>'.
      Types of property 'TYPE' are incompatible.
        Type '{ type: Types.One; value: string; } | { type: Types.Two; }' is not assignable to type 'Validating<Types>'.
          Type '{ type: Types.Two; }' is not assignable to type 'Validating<Types>'.
    

    I also had a second idea which is even more broken, but is nicer if possible.

    const Validating: Describe<Validating> = dynamic((v: any) =>
      object({
        type: literal(Types.One),
        value: v.type === Types.One ? string() : never(),
      }),
    );
    
    assert({ type: Types.One, value: "Value!" }, Validating);
    assert({ type: Types.Two }, Validating);
    

    I think this is related to #724, but not quite the same.

    opened by dsluijk 1
  • Adding rest props for object-type

    Adding rest props for object-type

    First of all, thank you for this convenient tree-shakeable lib!

    Sometimes we don't need to know, what the keys are in our object, but only their types E.g. We keep addresses, added by user in structure like that:

    addresses: {
      [addressName: string]: string
    }
    

    TS allows us to do it

    What if to add similar behavior in object structure, using a Symbol for that. Symbol lets you distinguish this props from any others:

    // Inside Superstruct lib
    export const anyProp = Symbol()
    ...
    const isAnyProp = key === anyProp
    ...
    
    // On Superstruct's user side
    import { object, anyProp } from 'superstruct'
    
    const Addresses = object({
      requiredAddressField: string,
      [anyProp]: string
    })
    
    opened by vtrushin 0
  • Show object properties and values in failure message

    Show object properties and values in failure message

    This will help for debugging when the assert has failed.

    When a value is an object, the message for failure contains [object Object].

    Adding a stringify on the value if its type is object seems like the quickiest win for easier debugging.

    opened by abouteiller-niji 0
  • Feature Request: Infer the other way.

    Feature Request: Infer the other way.

    The Infer function is great because it allows us to get the output types of a given struct. However, it would also be great to be able to get the input types of a given struct. I'll give an example of the difference:

    The following struct will always output a number.

    const MyNumber = coerce(number(), string(), (value) => parseFloat(value))
    type OutputType = number // generated by Infer
    

    However, it can accept numbers & strings. So the input type would be:

    type InputType = string | number
    

    I need a way to Infer the input type of a struct. Also, I think this would be a great addition to the already great lib.

    feature ♥ help please 
    opened by ivands 2
Validate your forms, frontend, without writing a single line of javascript

Parsley JavaScript form validation, without actually writing a single line of JavaScript! Version 2.9.2 Doc See index.html and doc/ Requirements jQuer

Guillaume Potier 9k Dec 27, 2022
[DISCONTINUED] jQuery plugin that makes it easy to validate user input while keeping your HTML markup clean from javascript code.

jQuery Form Validator [DISCONTINUED] Validation framework that let's you configure, rather than code, your validation logic. I started writing this pl

Victor Jonsson 976 Dec 30, 2022
jQuery library to validate html forms. compatible with bootstrap v4 and bootstrap v3

jQuery form validation jQuery form validation is a library that helps you to validate your HTML form, it's completable with both Bootstrap 3 and Boots

Bassam Nabriss 33 Jun 10, 2021
Validate properties and well known annotations in your Backstage catalog-info.yaml files.

Backstage entity validator This package can be used as a GitHub action or a standalone node.js module GitHub action Inputs path Optional Path to the c

Roadie 39 Dec 26, 2022
Validate for XML schema and returns all the possible failures

detailed-xml-validator Validate for XML schema and returns all the possible failures Sample Rules file <?xml version = "1.0"?> <students nillable="fa

Natural Intelligence 11 Dec 20, 2022
The best @jquery plugin to validate form fields. Designed to use with Bootstrap + Zurb Foundation + Pure + SemanticUI + UIKit + Your own frameworks.

FormValidation - Download http://formvalidation.io - The best jQuery plugin to validate form fields, designed to use with: Bootstrap Foundation Pure S

FormValidation 2.8k Mar 29, 2021
This Login Form made using React hooks , React Js , Css, Json. This form have 3 inputs, it also validate those inputs & it also having length limitations.

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Yogesh Sharma 0 Jan 3, 2022
Validate graphql operations against a schema

@graphql-validate With the power of GraphQL-Tools and GraphQL-JS, we are able to provide a smooth experience for validation your GraphQL operations du

Saihajpreet Singh 13 Dec 23, 2022
A library for validate a string using regular expressions.

Fogex Form Regex Quickly and easily check if the content is valid. Installation npm install fogex or yarn add fogex Usage import fogex from 'fogex';

null 5 May 5, 2022
Super Fast Complex Object Validator for Javascript(& Typescript).

Super Fast Object Validator for Javascript(& Typescript). Safen supports the syntax similar to the type script interface. This makes it easy to create

Changwan Jun 31 Nov 25, 2022
Simple and basic javascript form validations

JavaScript-Form-Validations Simple and basic javascript form validations Table of Validations: S. No. Type of validation Link 1 Non-empty text field h

MAINAK CHAUDHURI 23 Dec 17, 2022
A simple credit cards validation library in JavaScript

creditcard.js A simple credit cards validation library in JavaScript. Project website: https://contaazul.github.io/creditcard.js Install creditcard.js

ContaAzul 323 Jan 7, 2023
Simple password validator made with Javascript 💛

Password Validator Simple password validator made with Javascript ?? Branch history base-code: a complex logic to password validator. In next branches

Lais Frigério 8 Jul 25, 2022
GUI for editing, visualizing, and manipulating JSON data

JSON-Splora JSON-Splora is a GUI for editing, visualizing, and manipulating JSON data with jq or JavaScript. Design Built with Electron Editor and out

Wells Johnston 1.8k Dec 25, 2022
Themis is a validation and processing library that helps you always make sure your data is correct.

Dataffy Themis - The advanced validation library Themis is a validation and processing library that helps you always make sure your data is correct. ·

Dataffy 14 Oct 27, 2022
The most powerful data validation library for JS

joi The most powerful schema description language and data validator for JavaScript. Installation npm install joi Visit the joi.dev Developer Portal f

Sideway Inc. 19.6k Jan 4, 2023
Fast, compiled, eval-free data validator/transformer

spectypes Fast, compiled, eval-free data validator/transformer Features really fast, can be even faster than ajv detailed errors, failure will result

null 65 Dec 29, 2022
TypeScript-first schema validation for h3 and Nuxt applications

h3-zod Validate h3 and Nuxt 3 requests using zod schema's. Install npm install h3-zod Usage import { createServer } from 'http' import { createApp } f

Robert Soriano 48 Dec 28, 2022
🦩 Joi like validations for TypeScript

?? Computed Types Runtime validation types for TypeScript. Computed-Types (formerly: Funval) is a strongly-typed validation library for TypeScript. Us

Neuledge 338 Jan 4, 2023