1.0.1 • Published 3 years ago

@nonamenpm/type-validate v1.0.1

Weekly downloads
-
License
ISC
Repository
-
Last release
3 years ago

Use case

Runtime type validation is usually preferred when using config files for a program, to check if the user-supplied data is valid, or, when making tests, you want to check the structure of a given object, without actually having pre-determined values.

Example

The following program uses an example config for VSCode's jsconfig.json config file, and provides an hypothetical rule to validate it.

// config.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6"
  },
  "include": ["src/**/*"]
}

// index.ts

import validate, { Optional, StringType, Branch, ArrayOf, Choice } from 'type-validate'
import { readFileSync } from 'fs'

// taking in consideration only `compilerOptions` and `include`
const rule = {
    compilerOptions: Optional(Branch({
        module: Optional(Choice('amd', 'commonJS', 'es2015', 'es6', 'esnext', 'none', 'system', 'umd')),
        target: Optional(Choice('es3', 'es5', 'es6', 'es2015', 'es2015', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext'))
    }))
    include: Optional(ArrayOf(StringType))
}

validate(rule, JSON.parse(readFileSync('config.json'))) // in this case, everything is valid, and the function does not throw

Usage

validate<T extends ValidationRule>(rules: Record<string, ValidationRuleConstructor<T>>, toValidate: Record<string, unknown>): never | void

Takes a set of "type rules" and compares them to the input given to the function, when the input doesn't validate, this function throws a ValidationError containing the expected type along with the key in the object that failed.

Example

import validate, {
  StringType,
  NumberType,
  BooleanType,
  ObjectType,
  Optional,
} from 'type-validate';

const rules = {
  name: StringType,
  age: Optional(NumberType),
  married: BooleanType,
  additionalInfo: Optional(ObjectType),
};

validate(rules, { name: 'Foo', married: false }); // => doesn't throw, no rules were violated
validate(rules, { name: {}, age: 42, married: false, additionalInfo: {} }); // => throws, `name` is not a `string`
validate(rules, { age: 42, additionalInfo: {} }); // => throws, `name` and `married` aren't `Optional`

Any

Wildcard rule that accepts everything.

AnyOf

Accepts multiple rules as an input, returns true if at least one of the rules validates.

Example

validate({ example: AnyOf(StringType, NumberType) }, { example: 'foo' }); // => valid
validate({ example: AnyOf(StringType, NumberType) }, { example: 42 }); // => valid
validate({ example: AnyOf(StringType, NumberType) }, { exmple: true }); // => invalid, because we don't accept `BooleanType`

None

Accepts only undefined

Not

Negates the supplied rule

Example

validate({ example: Not(StringType) }, { example: 42 }); // => valid
validate({ example: Not(StringType) }, { example: true }); // => valid
validate({ example: Not(StringType) }, { example: undefined }); // => valid
validate({ example: Not(StringType) }, { example: 'foo' }); // => invalid, we do not accept `StringType`

ArrayOf

Validates any array that has every element that follows at least 1 rule.

Example

validate(
  { example: ArrayOf(StringType, NumberType, BooleanType, None) },
  { example: ['foo', 42] }
); // => valid
validate(
  { example: ArrayOf(StringType, NumberType, BooleanType, None) },
  { example: [true] }
); // => valid
validate(
  { example: ArrayOf(StringType, NumberType, BooleanType, None) },
  { example: [] }
); // => valid
validate(
  { example: ArrayOf(StringType, NumberType, BooleanType, None) },
  { example: [{}] }
); // => invalid, we don't accept `ObjectType`
validate(
  { example: ArrayOf(StringType, NumberType, BooleanType, None) },
  { example: undefined }
); // => invalid, the array is not `Optional`

ArrayStrict

Validates an array only if it follows the same structure as the rule.

Example

validate(
  { example: ArrayStrict(StringType, NumberType) },
  { example: ['foo', 42] }
); // => valid
validate(
  { example: ArrayStrict(StringType, NumberType) },
  { example: ['foo'] }
); // => invalid, missing `NumberType`
validate({ example: ArrayStrict(StringType, NumberType) }, { example: [42] }); // => invalid, missing `StringType`
validate(
  { example: ArrayStrict(StringType, NumberType) },
  { example: [42, 'foo'] }
); // => invalid, the order of the elements is reversed
validate({ example: ArrayStrict(StringType, NumberType) }, { example: [] }); // => invalid, array is empty
validate(
  { example: ArrayStrict(StringType, NumberType) },
  { example: ['foo', 42, 43] }
); // => invalid, does not follow the structure of the rule

Branch

Validates an object.

Example

validate({ example: Branch({ example2: Not(None) })) }, { example: { example2: 42 } }) // => valid
validate({ example: Branch({ example2: Not(None) })) }, { example: {} }) // => invalid, example2 is undefined (NOTE: if example2 was accepting `Any`, this example would be valid)
validate({ example: Branch({ example2: Not(None) })) }, { example: [] }) // => invalid, example is not an object

Optional

Makes the supplied rule optional.

import validate, { Optional, NumberType } from 'type-validate';

const rule = {
  age: Optional(NumberType),
};

validate(rule, {}); // => valid
validate(rule, { age: 27 }); // => valid
validate(rule, { age: '27' }); // => invalid

Choice

Takes multiple arguments as choices, throws when the value in the object isn't present in Choice.

Example

import validateRc, {
  StringType,
  NumberType,
  BooleanType,
  None,
  Optional,
  Choice,
} from 'validate-rc';

validate(
  { example: ArrayOf(StringType, NumberType, BooleanType, None) },
  { example: ['foo', 42] }
); // => valid
validate(
  { example: ArrayOf(StringType, NumberType, BooleanType, None) },
  { example: [true] }
); // => valid
validate(
  { example: ArrayOf(StringType, NumberType, BooleanType, None) },
  { example: [] }
); // => valid
validate(
  { example: ArrayOf(StringType, NumberType, BooleanType, None) },
  { example: [{}] }
); // => invalid, we don't accept `ObjectType`
validate(
  { example: ArrayOf(StringType, NumberType, BooleanType, None) },
  { example: undefined }
); // => invalid, the array is not `Optional`

Handling Errors

validate throws a ValidationError when the object given doesn't match the rule. It contains what it expected and the key that contains the invalid data.

Handling example

import validate, { ValidationError } from 'type-validate';

const rule = {
  /* rules */
};
const config = require(process.cwd() + '/.dummyrc.js');

try {
  validate(rule, config);
} catch (e) {
  if (e instanceof ValidationError) {
    console.log(`Expected type '${e.expected}' at '${e.key}'`);
    process.exit(1);
  } else throw e;
}