ts-prime
Version:
A utility library for JavaScript and Typescript.
444 lines (426 loc) • 10.9 kB
text/typescript
import {
isString,
isBoolean,
isArray,
isDefined,
isNil,
isFunction,
isError,
isNumber,
isObject,
isPromise,
isNot,
haveKeys,
} from './guards';
type TestObj =
| boolean
| string
| { a: string }
| (() => void)
| number[]
| Date
| undefined
| null
| Error
| number
| Promise<number>;
function assertType<T>(data: T): T {
return data;
}
const dataProvider = (
t:
| 'string'
| 'boolean'
| 'object'
| 'function'
| 'array'
| 'date'
| 'undefined'
| 'null'
| 'error'
| 'number'
| 'promise'
): TestObj => {
switch (t) {
case 'number':
return 5;
case 'array':
return [1, 2, 3];
case 'boolean':
return false;
case 'date':
return new Date();
case 'function':
return () => { };
case 'null':
return null;
case 'promise':
return Promise.resolve(5);
case 'string':
return 'text';
case 'object':
return { a: 'asd' };
case 'error':
return new Error('asd');
}
return 'text';
};
describe('Describe guards behavior', () => {
test('isString: should work as type guard', () => {
const data = dataProvider('string');
if (isString(data)) {
expect(typeof data).toEqual('string');
assertType<string>(data);
}
});
test('isString: should work even if data type is unknown', () => {
const data: unknown = dataProvider('string');
if (isString(data)) {
expect(typeof data).toEqual('string');
assertType<string>(data);
}
});
test('isString: should work with literal types', () => {
const data = (): 'a' | 'b' | 'c' | number => {
return 'a';
};
const x = data();
if (isString(x)) {
expect(typeof x).toEqual('string');
assertType<'a' | 'b' | 'c'>(x);
}
});
test('isString: should work as type guard in array', () => {
const data = [
dataProvider('error'),
dataProvider('string'),
dataProvider('function'),
dataProvider('null'),
dataProvider('array'),
dataProvider('boolean'),
].filter(isString);
expect(data.every(c => typeof c === 'string')).toEqual(true);
assertType<string[]>(data);
});
test('isBoolean: should work as type guard', () => {
const data = dataProvider('boolean');
if (isBoolean(data)) {
expect(typeof data).toEqual('boolean');
assertType<boolean>(data);
}
const data1: unknown = dataProvider('boolean');
if (isBoolean(data1)) {
expect(typeof data1).toEqual('boolean');
assertType<boolean>(data1);
}
const data2: any = dataProvider('boolean');
if (isBoolean(data2)) {
expect(typeof data2).toEqual('boolean');
assertType<boolean>(data2);
}
});
test('isBoolean: should work as type guard in filter', () => {
const data = [
dataProvider('error'),
dataProvider('array'),
dataProvider('function'),
dataProvider('null'),
dataProvider('array'),
dataProvider('boolean'),
].filter(isBoolean);
expect(data.every(c => typeof c === 'boolean')).toEqual(true);
assertType<boolean[]>(data);
});
test('isArray: should work as type guard', () => {
const data = dataProvider('array');
if (isArray(data)) {
expect(Array.isArray(data)).toEqual(true);
assertType<number[]>(data);
}
const data1: unknown = dataProvider('array');
if (isArray(data1)) {
expect(Array.isArray(data1)).toEqual(true);
assertType<readonly unknown[]>(data1);
}
});
test('isArray: should work as type guard in filter', () => {
const data = [
dataProvider('error'),
dataProvider('array'),
dataProvider('function'),
dataProvider('null'),
dataProvider('array'),
dataProvider('date'),
].filter(isArray);
expect(data.every(c => Array.isArray(c))).toEqual(true);
assertType<number[][]>(data);
});
test('isDefined": should work as type guard', () => {
const data = dataProvider('date');
if (isDefined(data)) {
expect(data instanceof Date).toEqual(true);
assertType<
| boolean
| string
| { a: string }
| (() => void)
| number[]
| Date
| Error
| number
| Promise<number>
>(data);
}
});
test('isDefined: should work as type guard in filter', () => {
const data = [
dataProvider('error'),
dataProvider('array'),
dataProvider('function'),
dataProvider('null'),
dataProvider('number'),
].filter(isDefined);
expect(data.length === 4).toEqual(true);
assertType<
(
| string
| number
| boolean
| {
a: string;
}
| (() => void)
| number[]
| Date
| Error
| Promise<number>
)[]
>(data);
});
test('isNil: should work as type guard', () => {
const data = dataProvider('null');
if (isNil(data)) {
expect(data).toEqual(null);
assertType<undefined | null>(data);
}
});
test('isNil: should work as type guard in filter', () => {
const data = [
dataProvider('error'),
dataProvider('array'),
dataProvider('function'),
dataProvider('function'),
dataProvider('null'),
dataProvider('number'),
].filter(isNil);
expect(data.every(c => c == null)).toEqual(true);
assertType<(null | undefined)[]>(data);
});
test('isFunction: should work as type guard', () => {
const data = dataProvider('null');
if (isFunction(data)) {
expect(data).toEqual(null);
assertType<() => void>(data);
}
});
test('isFunction: should work as type guard in filter', () => {
const data = [
dataProvider('error'),
dataProvider('array'),
dataProvider('function'),
dataProvider('function'),
dataProvider('object'),
dataProvider('number'),
].filter(isFunction);
expect(data.every(c => typeof c === 'function')).toEqual(true);
assertType<(() => void)[]>(data);
});
test('isError: should work as type guard', () => {
const data = dataProvider('error');
if (isError(data)) {
expect(data instanceof Error).toEqual(true);
assertType<Error>(data);
}
});
test('isError: should work as type guard in filter', () => {
const data = [
dataProvider('error'),
dataProvider('array'),
dataProvider('boolean'),
dataProvider('function'),
dataProvider('object'),
dataProvider('number'),
].filter(isError);
expect(data.every(c => c instanceof Error)).toEqual(true);
assertType<Error[]>(data);
});
test('isNumber: should work as type guard', () => {
const data = dataProvider('number');
if (isNumber(data)) {
expect(typeof data).toEqual('number');
assertType<number>(data);
}
});
test('isNumber: should work as type guard in filter', () => {
const data = [
dataProvider('promise'),
dataProvider('array'),
dataProvider('boolean'),
dataProvider('function'),
dataProvider('object'),
dataProvider('number'),
].filter(isNumber);
expect(data.every(c => typeof c === 'number')).toEqual(true);
assertType<number[]>(data);
});
test('isObject: should work as type guard', () => {
const data = dataProvider('object');
if (isObject(data)) {
expect(typeof data).toEqual('object');
assertType<
| {
a: string;
}
| Date
| Error
| Promise<number>
>(data);
}
});
test('isObject: should work as type guard', () => {
const data = { data: 5 } as ReadonlyArray<number> | { data: number };
if (isObject(data)) {
expect(typeof data).toEqual('object');
assertType<{ data: number }>(data);
}
});
test('isObject: should work as type guard', () => {
const data = { data: 5 } as Array<number> | { data: number };
if (isObject(data)) {
expect(typeof data).toEqual('object');
assertType<{ data: number }>(data);
}
});
test('isObject: should work as type guard in filter', () => {
const data = [
dataProvider('promise'),
dataProvider('array'),
dataProvider('boolean'),
dataProvider('function'),
dataProvider('object'),
].filter(isObject);
expect(data.every(c => typeof c === 'object' && !Array.isArray(c))).toEqual(
true
);
assertType<
(
| {
a: string;
}
| Date
| Error
| Promise<number>
)[]
>(data);
});
test('isPromise: should work as type guard', () => {
const data = dataProvider('promise');
if (isPromise(data)) {
expect(data instanceof Promise).toEqual(true);
assertType<Promise<number>>(data);
}
});
test('isPromise: should work as type guard in filter', () => {
const data = [
dataProvider('promise'),
dataProvider('array'),
dataProvider('boolean'),
dataProvider('function'),
].filter(isPromise);
expect(data.every(c => c instanceof Promise)).toEqual(true);
assertType<Promise<number>[]>(data);
});
test('haveKeys: should work as type guard in filter', () => {
const data = [
{
x: 4,
},
{
a: 1,
b: 2,
},
{
a: 1,
b: 5,
},
].filter(haveKeys(['a', 'b']));
expect(data).toEqual([
{
a: 1,
b: 2,
},
{
a: 1,
b: 5,
},
]);
assertType<{ a: number; b: number }[]>(data);
});
test('haveKeys: should work as type guard in filter', () => {
const definedKeys = haveKeys(['a', 'b']);
const obj = {
x: 4,
};
if (definedKeys(obj)) {
assertType<{
x: number;
a: unknown;
b: unknown;
}>(obj);
}
});
test('isNot: should work as type guard', () => {
const data = dataProvider('promise');
if (isNot(isString)(data)) {
assertType<
| number
| boolean
| {
a: string;
}
| (() => void)
| number[]
| Date
| Error
| Promise<number>
| null
| undefined
>(data);
expect(data instanceof Promise).toEqual(true);
}
});
test('isNot: should work as type guard in filter', () => {
const data = [
dataProvider('promise'),
dataProvider('array'),
dataProvider('boolean'),
dataProvider('function'),
];
const result = data.filter(isNot(isPromise));
expect(result.some(c => c instanceof Promise)).toEqual(false);
assertType<
(
| boolean
| string
| { a: string }
| (() => void)
| number[]
| Date
| undefined
| null
| Error
| number
)[]
>(result);
});
});