diff --git a/packages/common/src/guard.test.ts b/packages/common/src/guard.test.ts new file mode 100644 index 0000000..a208961 --- /dev/null +++ b/packages/common/src/guard.test.ts @@ -0,0 +1,60 @@ +import {guard, isNumber, isString, isDefined, isUndefined, isNull} from './guard' + +function getNumber(n: number | null): number | null { + return n +} + +function getString(str: string | undefined | null): string | undefined | null { + return str +} + +describe('guard', () => { + + describe('converts T | undefined | null to T', () => { + describe('isDefined', () => { + it('converts T | undefined | null to T', () => { + const s1: string | undefined | null = getString('test') + const s2: string = guard(isDefined, s1) + expect(s2).toBe('test') + }) + }) + + describe('isString', () => { + it('converts string | undefined | null to string', () => { + const s1: string | undefined | null = getString('test') + const s2: string = guard(isString, s1) + expect(s2).toBe('test') + }) + }) + + describe('isNumber', () => { + it('converts number | undefined | null to number', () => { + const n1: number | undefined | null = getNumber(1) + const n2: number = guard(isNumber, n1) + expect(n2).toBe(1) + }) + }) + + describe('isUndefined', () => { + const s1: string | undefined | null = getString(undefined) + const s2: undefined = guard(isUndefined, s1) + expect(s2).toBe(undefined) + }) + + describe('isNull', () => { + const s1: string | undefined | null = getString(null) + const s2: null = guard(isNull, s1) + expect(s2).toBe(null) + }) + + }) + + describe('errors', () => { + it('guards against unexpected types', () => { + const s1: string | undefined | null = getString(null) + expect(() => guard(isString, s1)) + .toThrowError('Value null does not satisfy constraint: isString') + }) + }) + +}) diff --git a/packages/common/src/guard.ts b/packages/common/src/guard.ts new file mode 100644 index 0000000..f6b6956 --- /dev/null +++ b/packages/common/src/guard.ts @@ -0,0 +1,35 @@ +type CheckType = (t: unknown) => t is T + +export function guard( + checkType: CheckType, + t: unknown, +): Expected { + if (!checkType(t)) { + throw new Error( + `Value ${t} does not satisfy constraint: ${checkType.name}`) + } + + return t +} + +export function isUndefined(t: unknown): t is undefined { + return t === undefined +} + +export function isNull(t: unknown): t is null { + return t === null +} + +export function isDefined( + t: unknown, +): t is T { + return t !== undefined && t !== null +} + +export function isNumber(t: unknown): t is number { + return typeof t === 'number' +} + +export function isString(t: unknown): t is string { + return typeof t === 'string' +} diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index d1ce5c8..d7a101b 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -6,6 +6,7 @@ export * from './ILogger' export * from './IRole' export * from './StringUtils' export * from './filterProps' +export * from './guard' export * from './indexBy' export * from './types' export * from './without'