diff --git a/readme.md b/readme.md index 9d0d687..1da8fea 100644 --- a/readme.md +++ b/readme.md @@ -94,6 +94,16 @@ Returns a predicate that verifies if the value matches at least one of the given ow('foo', ow.any(ow.string.maxLength(3), ow.number)); ``` +### ow.optional.{type} + +Makes the predicate optional. An optional predicate means that it doesn't fail if the value is `undefined`. + +```ts +ow(1, ow.optional.number); + +ow(undefined, ow.optional.number); +``` + ### ow.{type} All the below types return a predicate. Every predicate has some extra operators that you can use to test the value even more fine-grained. diff --git a/source/index.ts b/source/index.ts index 0d86e1f..bc641bb 100644 --- a/source/index.ts +++ b/source/index.ts @@ -1,28 +1,17 @@ import callsites from 'callsites'; import {inferLabel} from './lib/utils/infer-label'; import {Predicate} from './lib/predicates/predicate'; -import {AnyPredicate} from './lib/predicates/any'; import {testSymbol, BasePredicate, isPredicate} from './lib/predicates/base-predicate'; -import {StringPredicate} from './lib/predicates/string'; -import {NumberPredicate} from './lib/predicates/number'; -import {BooleanPredicate} from './lib/predicates/boolean'; -import {ArrayPredicate} from './lib/predicates/array'; -import {ObjectPredicate} from './lib/predicates/object'; -import {DatePredicate} from './lib/predicates/date'; -import {ErrorPredicate} from './lib/predicates/error'; -import {MapPredicate} from './lib/predicates/map'; -import {WeakMapPredicate} from './lib/predicates/weak-map'; -import {SetPredicate} from './lib/predicates/set'; -import {WeakSetPredicate} from './lib/predicates/weak-set'; - -type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array; +import modifiers, {Modifiers} from './modifiers'; +import predicates, {Predicates} from './predicates'; /** * @hidden */ export type Main = (value: T, label: string | Function, predicate: BasePredicate) => void; -export interface Ow { +// Extends is only necessary for the generated documentation to be cleaner. The loaders below infer the correct type. +export interface Ow extends Modifiers, Predicates { /** * Test if the value matches the predicate. Throws an `ArgumentError` if the test fails. * @@ -38,138 +27,6 @@ export interface Ow { * @param predicate Predicate to test against. */ (value: T, label: string, predicate: BasePredicate): void; - /** - * Test the value to be a string. - */ - readonly string: StringPredicate; - /** - * Test the value to be a number. - */ - readonly number: NumberPredicate; - /** - * Test the value to be a boolean. - */ - readonly boolean: BooleanPredicate; - /** - * Test the value to be undefined. - */ - readonly undefined: Predicate; - /** - * Test the value to be null. - */ - readonly null: Predicate; - /** - * Test the value to be null or undefined. - */ - readonly nullOrUndefined: Predicate; - /** - * Test the value to be not a number. - */ - readonly nan: Predicate; - /** - * Test the value to be a Symbol. - */ - readonly symbol: Predicate; - /** - * Test the value to be an array. - */ - readonly array: ArrayPredicate; - /** - * Test the value to be an object. - */ - readonly object: ObjectPredicate; - /** - * Test the value to be a Date. - */ - readonly date: DatePredicate; - /** - * Test the value to be an Error. - */ - readonly error: ErrorPredicate; - /** - * Test the value to be a Map. - */ - readonly map: MapPredicate; - /** - * Test the value to be a WeakMap. - */ - readonly weakMap: WeakMapPredicate; - /** - * Test the value to be a Set. - */ - readonly set: SetPredicate; - /** - * Test the value to be a WeakSet. - */ - readonly weakSet: WeakSetPredicate; - /** - * Test the value to be a Function. - */ - readonly function: Predicate; - /** - * Test the value to be a Buffer. - */ - readonly buffer: Predicate; - /** - * Test the value to be a RegExp. - */ - readonly regExp: Predicate; - /** - * Test the value to be a Promise. - */ - readonly promise: Predicate>; - /** - * Test the value to be a typed array. - */ - readonly typedArray: Predicate; - /** - * Test the value to be a Int8Array. - */ - readonly int8Array: Predicate; - /** - * Test the value to be a Uint8Array. - */ - readonly uint8Array: Predicate; - /** - * Test the value to be a Uint8ClampedArray. - */ - readonly uint8ClampedArray: Predicate; - /** - * Test the value to be a Int16Array. - */ - readonly int16Array: Predicate; - /** - * Test the value to be a Uint16Array. - */ - readonly uint16Array: Predicate; - /** - * Test the value to be a Int32Array. - */ - readonly int32Array: Predicate; - /** - * Test the value to be a Uint32Array. - */ - readonly uint32Array: Predicate; - /** - * Test the value to be a Float32Array. - */ - readonly float32Array: Predicate; - /** - * Test the value to be a Float64Array. - */ - readonly float64Array: Predicate; - /** - * Test the value to be a ArrayBuffer. - */ - readonly arrayBuffer: Predicate; - /** - * Test the value to be a DataView. - */ - readonly dataView: Predicate; - /** - * Test the value to be Iterable. - */ - readonly iterable: Predicate>; /** * Returns `true` if the value matches the predicate, otherwise returns `false`. * @@ -190,20 +47,6 @@ export interface Ow { * @param predicate Predicate used in the validator function. */ create(label: string, predicate: BasePredicate): (value: T) => void; - /** - * Test that the value matches at least one of the given predicates. - */ - any(p1: BasePredicate): AnyPredicate; - any(p1: BasePredicate, p2: BasePredicate): AnyPredicate; - any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate): AnyPredicate; - any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate): AnyPredicate; - any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate): AnyPredicate; - any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate, p6: BasePredicate): AnyPredicate; - any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate, p6: BasePredicate, p7: BasePredicate): AnyPredicate; - any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate, p6: BasePredicate, p7: BasePredicate, p8: BasePredicate): AnyPredicate; - any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate, p6: BasePredicate, p7: BasePredicate, p8: BasePredicate, p9: BasePredicate): AnyPredicate; - any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate, p6: BasePredicate, p7: BasePredicate, p8: BasePredicate, p9: BasePredicate, p10: BasePredicate): AnyPredicate; - any(...predicate: BasePredicate[]): AnyPredicate; } const test = (value: T, label: string | Function, predicate: BasePredicate) => { @@ -250,116 +93,12 @@ Object.defineProperties(ow, { test(value, labelOrPredicate as string, predicate as BasePredicate); } - }, - any: { - value: (...predicates: BasePredicate[]) => new AnyPredicate(predicates) - }, - string: { - get: () => new StringPredicate() - }, - number: { - get: () => new NumberPredicate() - }, - boolean: { - get: () => new BooleanPredicate() - }, - undefined: { - get: () => new Predicate('undefined') - }, - null: { - get: () => new Predicate('null') - }, - nullOrUndefined: { - get: () => new Predicate('nullOrUndefined') - }, - nan: { - get: () => new Predicate('nan') - }, - symbol: { - get: () => new Predicate('symbol') - }, - array: { - get: () => new ArrayPredicate() - }, - object: { - get: () => new ObjectPredicate() - }, - date: { - get: () => new DatePredicate() - }, - error: { - get: () => new ErrorPredicate() - }, - map: { - get: () => new MapPredicate() - }, - weakMap: { - get: () => new WeakMapPredicate() - }, - set: { - get: () => new SetPredicate() - }, - weakSet: { - get: () => new WeakSetPredicate() - }, - function: { - get: () => new Predicate('Function') - }, - buffer: { - get: () => new Predicate('Buffer') - }, - regExp: { - get: () => new Predicate('RegExp') - }, - promise: { - get: () => new Predicate('Promise') - }, - typedArray: { - get: () => new Predicate('TypedArray') - }, - int8Array: { - get: () => new Predicate('Int8Array') - }, - uint8Array: { - get: () => new Predicate('Uint8Array') - }, - uint8ClampedArray: { - get: () => new Predicate('Uint8ClampedArray') - }, - int16Array: { - get: () => new Predicate('Int16Array') - }, - uint16Array: { - get: () => new Predicate('Uint16Array') - }, - int32Array: { - get: () => new Predicate('Int32Array') - }, - uint32Array: { - get: () => new Predicate('Uint32Array') - }, - float32Array: { - get: () => new Predicate('Float32Array') - }, - float64Array: { - get: () => new Predicate('Float64Array') - }, - arrayBuffer: { - get: () => new Predicate('ArrayBuffer') - }, - dataView: { - get: () => new Predicate('DataView') - }, - iterable: { - get: () => new Predicate('Iterable') } }); -export default ow as Ow; +export default predicates(modifiers(ow)) as Ow; +export {BasePredicate, Predicate}; export { - BasePredicate, - Predicate, - AnyPredicate, StringPredicate, NumberPredicate, BooleanPredicate, @@ -370,5 +109,6 @@ export { MapPredicate, WeakMapPredicate, SetPredicate, - WeakSetPredicate -}; + WeakSetPredicate, + AnyPredicate +} from './predicates'; diff --git a/source/lib/predicates/any.ts b/source/lib/predicates/any.ts index 7aabc1c..73e93c8 100644 --- a/source/lib/predicates/any.ts +++ b/source/lib/predicates/any.ts @@ -1,13 +1,15 @@ import {ArgumentError} from '../argument-error'; import {BasePredicate, testSymbol} from './base-predicate'; import {Main} from '../..'; +import {PredicateOptions} from './predicate'; /** * @hidden */ export class AnyPredicate implements BasePredicate { constructor( - private readonly predicates: BasePredicate[] + private readonly predicates: BasePredicate[], + private readonly options: PredicateOptions = {} ) {} // tslint:disable completed-docs @@ -22,6 +24,10 @@ export class AnyPredicate implements BasePredicate { return; } catch (err) { + if (value === undefined && this.options.optional === true) { + return; + } + errors.push(`- ${err.message}`); } } diff --git a/source/lib/predicates/array.ts b/source/lib/predicates/array.ts index e02a8d2..5ef610c 100644 --- a/source/lib/predicates/array.ts +++ b/source/lib/predicates/array.ts @@ -1,13 +1,13 @@ import isEqual from 'lodash.isequal'; import ow from '../..'; -import {Predicate, Context} from './predicate'; +import {Predicate, PredicateOptions} from './predicate'; export class ArrayPredicate extends Predicate { /** * @hidden */ - constructor(context?: Context) { - super('array', context); + constructor(options?: PredicateOptions) { + super('array', options); } /** diff --git a/source/lib/predicates/boolean.ts b/source/lib/predicates/boolean.ts index 0187c88..544c4c4 100644 --- a/source/lib/predicates/boolean.ts +++ b/source/lib/predicates/boolean.ts @@ -1,11 +1,11 @@ -import {Predicate, Context} from './predicate'; +import {Predicate, PredicateOptions} from './predicate'; export class BooleanPredicate extends Predicate { /** * @hidden */ - constructor(context?: Context) { - super('boolean', context); + constructor(options?: PredicateOptions) { + super('boolean', options); } /** diff --git a/source/lib/predicates/date.ts b/source/lib/predicates/date.ts index 76190ef..c89afeb 100644 --- a/source/lib/predicates/date.ts +++ b/source/lib/predicates/date.ts @@ -1,11 +1,11 @@ -import {Predicate, Context} from './predicate'; +import {Predicate, PredicateOptions} from './predicate'; export class DatePredicate extends Predicate { /** * @hidden */ - constructor(context?: Context) { - super('date', context); + constructor(options?: PredicateOptions) { + super('date', options); } /** diff --git a/source/lib/predicates/error.ts b/source/lib/predicates/error.ts index 30f1d37..1e57988 100644 --- a/source/lib/predicates/error.ts +++ b/source/lib/predicates/error.ts @@ -1,11 +1,11 @@ -import {Predicate, Context} from './predicate'; +import {Predicate, PredicateOptions} from './predicate'; export class ErrorPredicate extends Predicate { /** * @hidden */ - constructor(context?: Context) { - super('error', context); + constructor(options?: PredicateOptions) { + super('error', options); } /** diff --git a/source/lib/predicates/map.ts b/source/lib/predicates/map.ts index fdfeffe..c110ea6 100644 --- a/source/lib/predicates/map.ts +++ b/source/lib/predicates/map.ts @@ -1,5 +1,5 @@ import isEqual from 'lodash.isequal'; -import {Predicate, Context} from './predicate'; +import {Predicate, PredicateOptions} from './predicate'; import hasItems from '../utils/has-items'; import ofType from '../utils/of-type'; @@ -7,8 +7,8 @@ export class MapPredicate extends Predicate> { /** * @hidden */ - constructor(context?: Context>) { - super('Map', context); + constructor(options?: PredicateOptions) { + super('Map', options); } /** diff --git a/source/lib/predicates/number.ts b/source/lib/predicates/number.ts index c6d2664..568ebfa 100644 --- a/source/lib/predicates/number.ts +++ b/source/lib/predicates/number.ts @@ -1,12 +1,12 @@ import is from '@sindresorhus/is'; -import {Predicate, Context} from './predicate'; +import {Predicate, PredicateOptions} from './predicate'; export class NumberPredicate extends Predicate { /** * @hidden */ - constructor(context?: Context) { - super('number', context); + constructor(options?: PredicateOptions) { + super('number', options); } /** diff --git a/source/lib/predicates/object.ts b/source/lib/predicates/object.ts index bf8a590..214d90e 100644 --- a/source/lib/predicates/object.ts +++ b/source/lib/predicates/object.ts @@ -1,7 +1,7 @@ import is from '@sindresorhus/is'; import dotProp from 'dot-prop'; import isEqual from 'lodash.isequal'; -import {Predicate, Context} from './predicate'; +import {Predicate, PredicateOptions} from './predicate'; import hasItems from '../utils/has-items'; import ofType from '../utils/of-type'; import ofTypeDeep from '../utils/of-type-deep'; @@ -10,8 +10,8 @@ export class ObjectPredicate extends Predicate { /** * @hidden */ - constructor(context?: Context) { - super('object', context); + constructor(options?: PredicateOptions) { + super('object', options); } /** diff --git a/source/lib/predicates/predicate.ts b/source/lib/predicates/predicate.ts index 38adb2e..e75713c 100644 --- a/source/lib/predicates/predicate.ts +++ b/source/lib/predicates/predicate.ts @@ -18,9 +18,15 @@ export interface Validator { /** * @hidden */ -export interface Context { +export interface PredicateOptions { + optional?: boolean; +} + +/** + * @hidden + */ +export interface Context extends PredicateOptions { validators: Validator[]; - label?: string; } /** @@ -32,12 +38,19 @@ export const validatorSymbol = Symbol('validators'); * @hidden */ export class Predicate implements BasePredicate { + private readonly context: Context = { + validators: [] + }; + constructor( private readonly type: string, - private readonly context: Context = { - validators: [] - } + private readonly options: PredicateOptions = {} ) { + this.context = { + ...this.context, + ...this.options + }; + const x = this.type[0].toLowerCase() + this.type.slice(1); this.addValidator({ @@ -59,7 +72,7 @@ export class Predicate implements BasePredicate { for (const {validator, message} of this.context.validators) { const result = validator(value); - if (result === true) { + if (result === true || (this.options.optional === true && value === undefined)) { continue; } diff --git a/source/lib/predicates/set.ts b/source/lib/predicates/set.ts index 88bd4a9..053fe5d 100644 --- a/source/lib/predicates/set.ts +++ b/source/lib/predicates/set.ts @@ -1,5 +1,5 @@ import isEqual from 'lodash.isequal'; -import {Predicate, Context} from './predicate'; +import {Predicate, PredicateOptions} from './predicate'; import hasItems from '../utils/has-items'; import ofType from '../utils/of-type'; @@ -7,8 +7,8 @@ export class SetPredicate extends Predicate> { /** * @hidden */ - constructor(context?: Context>) { - super('Set', context); + constructor(options?: PredicateOptions) { + super('Set', options); } /** diff --git a/source/lib/predicates/string.ts b/source/lib/predicates/string.ts index a49f8ff..4aff42f 100644 --- a/source/lib/predicates/string.ts +++ b/source/lib/predicates/string.ts @@ -1,12 +1,12 @@ import valiDate from 'vali-date'; -import {Predicate, Context} from './predicate'; +import {Predicate, PredicateOptions} from './predicate'; export class StringPredicate extends Predicate { /** * @hidden */ - constructor(context?: Context) { - super('string', context); + constructor(options?: PredicateOptions) { + super('string', options); } /** diff --git a/source/lib/predicates/weak-map.ts b/source/lib/predicates/weak-map.ts index fcf40a5..0bdfe84 100644 --- a/source/lib/predicates/weak-map.ts +++ b/source/lib/predicates/weak-map.ts @@ -1,12 +1,12 @@ -import {Predicate, Context} from './predicate'; +import {Predicate, PredicateOptions} from './predicate'; import hasItems from '../utils/has-items'; export class WeakMapPredicate extends Predicate> { /** * @hidden */ - constructor(context?: Context>) { - super('WeakMap', context); + constructor(options?: PredicateOptions) { + super('WeakMap', options); } /** diff --git a/source/lib/predicates/weak-set.ts b/source/lib/predicates/weak-set.ts index 9b08064..9d854f7 100644 --- a/source/lib/predicates/weak-set.ts +++ b/source/lib/predicates/weak-set.ts @@ -1,12 +1,12 @@ -import {Predicate, Context} from './predicate'; +import {Predicate, PredicateOptions} from './predicate'; import hasItems from '../utils/has-items'; export class WeakSetPredicate extends Predicate> { /** * @hidden */ - constructor(context?: Context>) { - super('WeakSet', context); + constructor(options?: PredicateOptions) { + super('WeakSet', options); } /** diff --git a/source/modifiers.ts b/source/modifiers.ts new file mode 100644 index 0000000..4738838 --- /dev/null +++ b/source/modifiers.ts @@ -0,0 +1,18 @@ +import predicates, {Predicates} from './predicates'; + +export interface Modifiers { + /** + * Make the following predicate optional so it doesn't fail when the value is `undefined`. + */ + readonly optional: Predicates; +} + +export default (object: T): T & Modifiers => { + Object.defineProperties(object, { + optional: { + get: () => predicates({}, {optional: true}) + } + }); + + return object as T & Modifiers; +}; diff --git a/source/predicates.ts b/source/predicates.ts new file mode 100644 index 0000000..9eea045 --- /dev/null +++ b/source/predicates.ts @@ -0,0 +1,289 @@ +import {StringPredicate} from './lib/predicates/string'; +import {NumberPredicate} from './lib/predicates/number'; +import {BooleanPredicate} from './lib/predicates/boolean'; +import {Predicate, PredicateOptions} from './lib/predicates/predicate'; +import {ArrayPredicate} from './lib/predicates/array'; +import {ObjectPredicate} from './lib/predicates/object'; +import {DatePredicate} from './lib/predicates/date'; +import {ErrorPredicate} from './lib/predicates/error'; +import {MapPredicate} from './lib/predicates/map'; +import {WeakMapPredicate} from './lib/predicates/weak-map'; +import {SetPredicate} from './lib/predicates/set'; +import {WeakSetPredicate} from './lib/predicates/weak-set'; +import {BasePredicate} from './lib/predicates/base-predicate'; +import {AnyPredicate} from './lib/predicates/any'; + +type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array; + +export interface Predicates { + /** + * Test the value to be a string. + */ + readonly string: StringPredicate; + /** + * Test the value to be a number. + */ + readonly number: NumberPredicate; + /** + * Test the value to be a boolean. + */ + readonly boolean: BooleanPredicate; + /** + * Test the value to be undefined. + */ + readonly undefined: Predicate; + /** + * Test the value to be null. + */ + readonly null: Predicate; + /** + * Test the value to be null or undefined. + */ + readonly nullOrUndefined: Predicate; + /** + * Test the value to be not a number. + */ + readonly nan: Predicate; + /** + * Test the value to be a Symbol. + */ + readonly symbol: Predicate; + /** + * Test the value to be an array. + */ + readonly array: ArrayPredicate; + /** + * Test the value to be an object. + */ + readonly object: ObjectPredicate; + /** + * Test the value to be a Date. + */ + readonly date: DatePredicate; + /** + * Test the value to be an Error. + */ + readonly error: ErrorPredicate; + /** + * Test the value to be a Map. + */ + readonly map: MapPredicate; + /** + * Test the value to be a WeakMap. + */ + readonly weakMap: WeakMapPredicate; + /** + * Test the value to be a Set. + */ + readonly set: SetPredicate; + /** + * Test the value to be a WeakSet. + */ + readonly weakSet: WeakSetPredicate; + /** + * Test the value to be a Function. + */ + readonly function: Predicate; + /** + * Test the value to be a Buffer. + */ + readonly buffer: Predicate; + /** + * Test the value to be a RegExp. + */ + readonly regExp: Predicate; + /** + * Test the value to be a Promise. + */ + readonly promise: Predicate>; + /** + * Test the value to be a typed array. + */ + readonly typedArray: Predicate; + /** + * Test the value to be a Int8Array. + */ + readonly int8Array: Predicate; + /** + * Test the value to be a Uint8Array. + */ + readonly uint8Array: Predicate; + /** + * Test the value to be a Uint8ClampedArray. + */ + readonly uint8ClampedArray: Predicate; + /** + * Test the value to be a Int16Array. + */ + readonly int16Array: Predicate; + /** + * Test the value to be a Uint16Array. + */ + readonly uint16Array: Predicate; + /** + * Test the value to be a Int32Array. + */ + readonly int32Array: Predicate; + /** + * Test the value to be a Uint32Array. + */ + readonly uint32Array: Predicate; + /** + * Test the value to be a Float32Array. + */ + readonly float32Array: Predicate; + /** + * Test the value to be a Float64Array. + */ + readonly float64Array: Predicate; + /** + * Test the value to be a ArrayBuffer. + */ + readonly arrayBuffer: Predicate; + /** + * Test the value to be a DataView. + */ + readonly dataView: Predicate; + /** + * Test the value to be Iterable. + */ + readonly iterable: Predicate>; + /** + * Test that the value matches at least one of the given predicates. + */ + any(p1: BasePredicate): AnyPredicate; + any(p1: BasePredicate, p2: BasePredicate): AnyPredicate; + any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate): AnyPredicate; + any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate): AnyPredicate; + any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate): AnyPredicate; + any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate, p6: BasePredicate): AnyPredicate; + any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate, p6: BasePredicate, p7: BasePredicate): AnyPredicate; + any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate, p6: BasePredicate, p7: BasePredicate, p8: BasePredicate): AnyPredicate; + any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate, p6: BasePredicate, p7: BasePredicate, p8: BasePredicate, p9: BasePredicate): AnyPredicate; + any(p1: BasePredicate, p2: BasePredicate, p3: BasePredicate, p4: BasePredicate, p5: BasePredicate, p6: BasePredicate, p7: BasePredicate, p8: BasePredicate, p9: BasePredicate, p10: BasePredicate): AnyPredicate; + any(...predicate: BasePredicate[]): AnyPredicate; +} + +export default (object: T, options?: PredicateOptions): T & Predicates => { + Object.defineProperties(object, { + string: { + get: () => new StringPredicate(options) + }, + number: { + get: () => new NumberPredicate(options) + }, + boolean: { + get: () => new BooleanPredicate(options) + }, + undefined: { + get: () => new Predicate('undefined', options) + }, + null: { + get: () => new Predicate('null', options) + }, + nullOrUndefined: { + get: () => new Predicate('nullOrUndefined', options) + }, + nan: { + get: () => new Predicate('nan', options) + }, + symbol: { + get: () => new Predicate('symbol', options) + }, + array: { + get: () => new ArrayPredicate(options) + }, + object: { + get: () => new ObjectPredicate(options) + }, + date: { + get: () => new DatePredicate(options) + }, + error: { + get: () => new ErrorPredicate(options) + }, + map: { + get: () => new MapPredicate(options) + }, + weakMap: { + get: () => new WeakMapPredicate(options) + }, + set: { + get: () => new SetPredicate(options) + }, + weakSet: { + get: () => new WeakSetPredicate(options) + }, + function: { + get: () => new Predicate('Function', options) + }, + buffer: { + get: () => new Predicate('Buffer', options) + }, + regExp: { + get: () => new Predicate('RegExp', options) + }, + promise: { + get: () => new Predicate('Promise', options) + }, + typedArray: { + get: () => new Predicate('TypedArray', options) + }, + int8Array: { + get: () => new Predicate('Int8Array', options) + }, + uint8Array: { + get: () => new Predicate('Uint8Array', options) + }, + uint8ClampedArray: { + get: () => new Predicate('Uint8ClampedArray', options) + }, + int16Array: { + get: () => new Predicate('Int16Array', options) + }, + uint16Array: { + get: () => new Predicate('Uint16Array', options) + }, + int32Array: { + get: () => new Predicate('Int32Array', options) + }, + uint32Array: { + get: () => new Predicate('Uint32Array', options) + }, + float32Array: { + get: () => new Predicate('Float32Array', options) + }, + float64Array: { + get: () => new Predicate('Float64Array', options) + }, + arrayBuffer: { + get: () => new Predicate('ArrayBuffer', options) + }, + dataView: { + get: () => new Predicate('DataView', options) + }, + iterable: { + get: () => new Predicate('Iterable', options) + }, + any: { + value: (...predicates: BasePredicate[]) => new AnyPredicate(predicates, options) + } + }); + + return object as T & Predicates; +}; + +export { + StringPredicate, + NumberPredicate, + BooleanPredicate, + ArrayPredicate, + ObjectPredicate, + DatePredicate, + ErrorPredicate, + MapPredicate, + WeakMapPredicate, + SetPredicate, + WeakSetPredicate, + AnyPredicate +}; diff --git a/source/test/optional.ts b/source/test/optional.ts new file mode 100644 index 0000000..17938b2 --- /dev/null +++ b/source/test/optional.ts @@ -0,0 +1,10 @@ +import test from 'ava'; +import m from '..'; + +test('optional', t => { + t.notThrows(() => m(1, m.optional.number)); + t.notThrows(() => m(undefined, m.optional.number)); + t.notThrows(() => m(undefined, m.optional.any(m.string, m.number))); + t.throws(() => m(null, m.optional.number), 'Expected argument to be of type `number` but received type `null`'); + t.throws(() => m('1' as any, m.optional.number), 'Expected argument to be of type `number` but received type `string`'); +});