Browse Source

Tweak typings (#107)

I need the predicate type for `ngx-ow`. While I was looking into that, I noticed that we got some types wrong, so fixed those as well and exported all the public available types.
master
Sam Verschueren 6 years ago
committed by Sindre Sorhus
parent
commit
4769c5bc5a
  1. 59
      source/index.ts
  2. 5
      source/lib/predicates/any.ts
  3. 8
      source/test/any.ts
  4. 4
      source/test/null-or-undefined.ts
  5. 6
      source/test/null.ts
  6. 19
      source/test/test.ts
  7. 8
      source/test/undefined.ts

59
source/index.ts

@ -1,6 +1,6 @@
import {Predicate} from './lib/predicates/predicate';
import {AnyPredicate} from './lib/predicates/any';
import {testSymbol} from './lib/predicates/base-predicate';
import {testSymbol, BasePredicate} from './lib/predicates/base-predicate';
import {StringPredicate} from './lib/predicates/string';
import {NumberPredicate} from './lib/predicates/number';
import {BooleanPredicate} from './lib/predicates/boolean';
@ -13,10 +13,7 @@ import {WeakMapPredicate} from './lib/predicates/weak-map';
import {SetPredicate} from './lib/predicates/set';
import {WeakSetPredicate} from './lib/predicates/weak-set';
/**
* @hidden
*/
export type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array;
type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array;
export interface Ow {
/**
@ -25,34 +22,34 @@ export interface Ow {
* @param value Value to test.
* @param predicate Predicate to test against.
*/
<T>(value: T, predicate: Predicate<T>): void;
<T>(value: T, predicate: BasePredicate<T>): void;
/**
* Returns `true` if the value matches the predicate, otherwise returns `false`.
*
* @param value Value to test.
* @param predicate Predicate to test against.
*/
isValid<T>(value: T, predicate: Predicate<T>): value is T;
isValid<T>(value: T, predicate: BasePredicate<T>): value is T;
/**
* Create a reusable validator.
*
* @param predicate Predicate used in the validator function.
*/
create<T>(predicate: Predicate<T>): (value: T) => void;
create<T>(predicate: BasePredicate<T>): (value: T) => void;
/**
* Test that the value matches at least one of the given predicates.
*/
any<T1>(p1: Predicate<T1>): Predicate<T1>;
any<T1, T2>(p1: Predicate<T1>, p2: Predicate<T2>): Predicate<T1 | T2>;
any<T1, T2, T3>(p1: Predicate<T1>, p2: Predicate<T2>, p3: Predicate<T3>): Predicate<T1 | T2 | T3>;
any<T1, T2, T3, T4>(p1: Predicate<T1>, p2: Predicate<T2>, p3: Predicate<T3>, p4: Predicate<T4>): Predicate<T1 | T2 | T3 | T4>;
any<T1, T2, T3, T4, T5>(p1: Predicate<T1>, p2: Predicate<T2>, p3: Predicate<T3>, p4: Predicate<T4>, p5: Predicate<T5>): Predicate<T1 | T2 | T3 | T4 | T5>;
any<T1, T2, T3, T4, T5, T6>(p1: Predicate<T1>, p2: Predicate<T2>, p3: Predicate<T3>, p4: Predicate<T4>, p5: Predicate<T5>, p6: Predicate<T6>): Predicate<T1 | T2 | T3 | T4 | T5 | T6>;
any<T1, T2, T3, T4, T5, T6, T7>(p1: Predicate<T1>, p2: Predicate<T2>, p3: Predicate<T3>, p4: Predicate<T4>, p5: Predicate<T5>, p6: Predicate<T6>, p7: Predicate<T7>): Predicate<T1 | T2 | T3 | T4 | T5 | T6 | T7>;
any<T1, T2, T3, T4, T5, T6, T7, T8>(p1: Predicate<T1>, p2: Predicate<T2>, p3: Predicate<T3>, p4: Predicate<T4>, p5: Predicate<T5>, p6: Predicate<T6>, p7: Predicate<T7>, p8: Predicate<T8>): Predicate<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8>;
any<T1, T2, T3, T4, T5, T6, T7, T8, T9>(p1: Predicate<T1>, p2: Predicate<T2>, p3: Predicate<T3>, p4: Predicate<T4>, p5: Predicate<T5>, p6: Predicate<T6>, p7: Predicate<T7>, p8: Predicate<T8>, p9: Predicate<T9>): Predicate<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9>;
any<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(p1: Predicate<T1>, p2: Predicate<T2>, p3: Predicate<T3>, p4: Predicate<T4>, p5: Predicate<T5>, p6: Predicate<T6>, p7: Predicate<T7>, p8: Predicate<T8>, p9: Predicate<T9>, p10: Predicate<T10>): Predicate<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9 | T10>;
any(...predicate: Predicate[]): Predicate;
any<T1>(p1: BasePredicate<T1>): AnyPredicate<T1>;
any<T1, T2>(p1: BasePredicate<T1>, p2: BasePredicate<T2>): AnyPredicate<T1 | T2>;
any<T1, T2, T3>(p1: BasePredicate<T1>, p2: BasePredicate<T2>, p3: BasePredicate<T3>): AnyPredicate<T1 | T2 | T3>;
any<T1, T2, T3, T4>(p1: BasePredicate<T1>, p2: BasePredicate<T2>, p3: BasePredicate<T3>, p4: BasePredicate<T4>): AnyPredicate<T1 | T2 | T3 | T4>;
any<T1, T2, T3, T4, T5>(p1: BasePredicate<T1>, p2: BasePredicate<T2>, p3: BasePredicate<T3>, p4: BasePredicate<T4>, p5: BasePredicate<T5>): AnyPredicate<T1 | T2 | T3 | T4 | T5>;
any<T1, T2, T3, T4, T5, T6>(p1: BasePredicate<T1>, p2: BasePredicate<T2>, p3: BasePredicate<T3>, p4: BasePredicate<T4>, p5: BasePredicate<T5>, p6: BasePredicate<T6>): AnyPredicate<T1 | T2 | T3 | T4 | T5 | T6>;
any<T1, T2, T3, T4, T5, T6, T7>(p1: BasePredicate<T1>, p2: BasePredicate<T2>, p3: BasePredicate<T3>, p4: BasePredicate<T4>, p5: BasePredicate<T5>, p6: BasePredicate<T6>, p7: BasePredicate<T7>): AnyPredicate<T1 | T2 | T3 | T4 | T5 | T6 | T7>;
any<T1, T2, T3, T4, T5, T6, T7, T8>(p1: BasePredicate<T1>, p2: BasePredicate<T2>, p3: BasePredicate<T3>, p4: BasePredicate<T4>, p5: BasePredicate<T5>, p6: BasePredicate<T6>, p7: BasePredicate<T7>, p8: BasePredicate<T8>): AnyPredicate<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8>;
any<T1, T2, T3, T4, T5, T6, T7, T8, T9>(p1: BasePredicate<T1>, p2: BasePredicate<T2>, p3: BasePredicate<T3>, p4: BasePredicate<T4>, p5: BasePredicate<T5>, p6: BasePredicate<T6>, p7: BasePredicate<T7>, p8: BasePredicate<T8>, p9: BasePredicate<T9>): AnyPredicate<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9>;
any<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(p1: BasePredicate<T1>, p2: BasePredicate<T2>, p3: BasePredicate<T3>, p4: BasePredicate<T4>, p5: BasePredicate<T5>, p6: BasePredicate<T6>, p7: BasePredicate<T7>, p8: BasePredicate<T8>, p9: BasePredicate<T9>, p10: BasePredicate<T10>): AnyPredicate<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9 | T10>;
any(...predicate: BasePredicate[]): AnyPredicate;
/**
* Test the value to be a string.
*/
@ -187,11 +184,11 @@ export interface Ow {
readonly iterable: Predicate<Iterable<any>>;
}
const main = <T>(value: T, predicate: Predicate<T> | AnyPredicate<T>) => (predicate as any)[testSymbol](value, main);
const main = <T>(value: T, predicate: BasePredicate<T>) => (predicate as any)[testSymbol](value, main);
Object.defineProperties(main, {
isValid: {
value: <T>(value: T, predicate: Predicate<T>) => {
value: <T>(value: T, predicate: BasePredicate<T>) => {
try {
main(value, predicate);
return true;
@ -201,10 +198,10 @@ Object.defineProperties(main, {
}
},
create: {
value: <T>(predicate: Predicate<T>) => (value: T) => main(value, predicate)
value: <T>(predicate: BasePredicate<T>) => (value: T) => main(value, predicate)
},
any: {
value: (...predicates: Predicate[]) => new AnyPredicate(predicates)
value: (...predicates: BasePredicate[]) => new AnyPredicate(predicates)
},
string: {
get: () => new StringPredicate()
@ -308,3 +305,19 @@ Object.defineProperties(main, {
});
export default main as Ow;
export {
BasePredicate,
Predicate,
AnyPredicate,
StringPredicate,
NumberPredicate,
BooleanPredicate,
ArrayPredicate,
ObjectPredicate,
DatePredicate,
ErrorPredicate,
MapPredicate,
WeakMapPredicate,
SetPredicate,
WeakSetPredicate
};

5
source/lib/predicates/any.ts

@ -1,14 +1,13 @@
import {ArgumentError} from '../argument-error';
import {Predicate} from './predicate';
import {BasePredicate, testSymbol} from './base-predicate';
import {Ow} from '../..';
/**
* @hidden
*/
export class AnyPredicate<T> implements BasePredicate<T> {
export class AnyPredicate<T = any> implements BasePredicate<T> {
constructor(
private readonly predicates: Predicate[]
private readonly predicates: BasePredicate[]
) {}
// tslint:disable completed-docs

8
source/test/any.ts

@ -1,7 +1,7 @@
import test from 'ava';
import m from '..';
const createError = (...errors: string[]) => {
export const createError = (...errors: string[]) => {
return [
'Any predicate failed with the following errors:',
...errors.map(error => `- ${error}`)
@ -19,3 +19,9 @@ test('any', t => {
'Expected argument to be of type `string` but received type `boolean`'
));
});
test('any inception', t => {
t.notThrows(() => m(1, m.any(m.number, m.any(m.string, m.boolean))));
t.notThrows(() => m('1', m.any(m.number, m.any(m.string, m.boolean))));
t.notThrows(() => m(true, m.any(m.number, m.any(m.string, m.boolean))));
});

4
source/test/null-or-undefined.ts

@ -10,6 +10,6 @@ test('nullOrUndefined', t => {
t.notThrows(() => m(x, m.nullOrUndefined));
t.notThrows(() => m(y, m.nullOrUndefined));
t.notThrows(() => m(y, m.nullOrUndefined.label('foo')));
t.throws(() => m('foo', m.nullOrUndefined), 'Expected argument to be of type `nullOrUndefined` but received type `string`');
t.throws(() => m('foo', m.nullOrUndefined.label('foo')), 'Expected `foo` to be of type `nullOrUndefined` but received type `string`');
t.throws(() => m('foo' as any, m.nullOrUndefined), 'Expected argument to be of type `nullOrUndefined` but received type `string`');
t.throws(() => m('foo' as any, m.nullOrUndefined.label('foo')), 'Expected `foo` to be of type `nullOrUndefined` but received type `string`');
});

6
source/test/null.ts

@ -7,7 +7,7 @@ test('null', t => {
t.notThrows(() => m(null, m.null));
t.notThrows(() => m(x, m.null));
t.notThrows(() => m(x, m.null.label('foo')));
t.throws(() => m(undefined, m.null), 'Expected argument to be of type `null` but received type `undefined`');
t.throws(() => m(undefined, m.null.label('foo')), 'Expected `foo` to be of type `null` but received type `undefined`');
t.throws(() => m('foo', m.null), 'Expected argument to be of type `null` but received type `string`');
t.throws(() => m(undefined as any, m.null), 'Expected argument to be of type `null` but received type `undefined`');
t.throws(() => m(undefined as any, m.null.label('foo')), 'Expected `foo` to be of type `null` but received type `undefined`');
t.throws(() => m('foo' as any, m.null), 'Expected argument to be of type `null` but received type `string`');
});

19
source/test/test.ts

@ -1,5 +1,6 @@
import test from 'ava';
import m from '..';
import {createError} from './any';
test('not', t => {
t.notThrows(() => m('foo!', m.string.not.alphanumeric));
@ -33,8 +34,11 @@ test('isValid', t => {
t.true(m.isValid(1, m.number));
t.true(m.isValid(1, m.number.equal(1)));
t.true(m.isValid('foo!', m.string.not.alphanumeric));
t.true(m.isValid('foo!', m.any(m.string, m.number)));
t.true(m.isValid(1, m.any(m.string, m.number)));
t.false(m.isValid(1 as any, m.string));
t.false(m.isValid(1 as any, m.number.greaterThan(2)));
t.false(m.isValid(true as any, m.any(m.string, m.number)));
});
test('reusable validator', t => {
@ -55,6 +59,21 @@ test('reusable validator with label', t => {
t.throws(() => checkUsername(5 as any), 'Expected `foo` to be of type `string` but received type `number`');
});
test('any-reusable validator', t => {
const checkUsername = m.create(m.any(m.string.includes('.'), m.string.minLength(3)));
t.notThrows(() => checkUsername('foo'));
t.notThrows(() => checkUsername('f.'));
t.throws(() => checkUsername('fo'), createError(
'Expected string to include `.`, got `fo`',
'Expected string to have a minimum length of `3`, got `fo`'
));
t.throws(() => checkUsername(5 as any), createError(
'Expected argument to be of type `string` but received type `number`',
'Expected argument to be of type `string` but received type `number`'
));
});
test('overwrite label', t => {
t.notThrows(() => m('foo', m.string.label('foo').label('bar')));
t.throws(() => m(12 as any, m.string.label('foo').label('bar')), 'Expected `bar` to be of type `string` but received type `number`');

8
source/test/undefined.ts

@ -8,8 +8,8 @@ test('undefined', t => {
t.notThrows(() => m(undefined, m.undefined));
t.notThrows(() => m(x, m.undefined));
t.notThrows(() => m(x, m.undefined.label('foo')));
t.throws(() => m(y, m.undefined), 'Expected argument to be of type `undefined` but received type `number`');
t.throws(() => m(y, m.undefined.label('foo')), 'Expected `foo` to be of type `undefined` but received type `number`');
t.throws(() => m(null, m.undefined), 'Expected argument to be of type `undefined` but received type `null`');
t.throws(() => m('foo', m.undefined), 'Expected argument to be of type `undefined` but received type `string`');
t.throws(() => m(y as any, m.undefined), 'Expected argument to be of type `undefined` but received type `number`');
t.throws(() => m(y as any, m.undefined.label('foo')), 'Expected `foo` to be of type `undefined` but received type `number`');
t.throws(() => m(null as any, m.undefined), 'Expected argument to be of type `undefined` but received type `null`');
t.throws(() => m('foo' as any, m.undefined), 'Expected argument to be of type `undefined` but received type `string`');
});

Loading…
Cancel
Save