diff --git a/readme.md b/readme.md index c59052c..2c35f9f 100644 --- a/readme.md +++ b/readme.md @@ -574,6 +574,36 @@ is.all(is.string, '🦄', [], 'unicorns'); //=> false ``` +##### .validDate(value) + +Returns `true` if the value is a valid date. + +All [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date) objects have an internal timestamp value which is the number of milliseconds since the [Unix epoch](https://developer.mozilla.org/en-US/docs/Glossary/Unix_time). When a new `Date` is constructed with bad inputs, no error is thrown. Instead, a new `Date` object is returned. But the internal timestamp value is set to `NaN`, which is an `'Invalid Date'`. Bad inputs can be an non-parsable date string, a non-numeric value or a number that is outside of the expected range for a date value. + +```js +const valid = new Date('2000-01-01'); + +is.date(valid); +//=> true +valid.getTime(); +//=> 946684800000 +valid.toUTCString(); +//=> 'Sat, 01 Jan 2000 00:00:00 GMT' +is.validDate(valid); +//=> true + +const invalid = new Date('Not a parsable date string'); + +is.date(invalid); +//=> true +invalid.getTime(); +//=> NaN +invalid.toUTCString(); +//=> 'Invalid Date' +is.validDate(invalid); +//=> false +``` + ##### .validLength(value) Returns `true` if the value is a safe integer that is greater than or equal to zero. diff --git a/source/index.ts b/source/index.ts index 2ee08d3..8c1d00b 100644 --- a/source/index.ts +++ b/source/index.ts @@ -128,6 +128,7 @@ const assertionTypeDescriptions = [ 'in range', 'predicate returns truthy for any value', 'predicate returns truthy for all values', + 'valid Date', 'valid length', 'whitespace string', ...objectTypeNames, @@ -311,6 +312,7 @@ const is = Object.assign( urlInstance: isUrlInstance, urlSearchParams: isUrlSearchParams, urlString: isUrlString, + validDate: isValidDate, validLength: isValidLength, weakMap: isWeakMap, weakRef: isWeakRef, @@ -760,6 +762,10 @@ export function isUrlString(value: unknown): value is string { } } +export function isValidDate(value: unknown): value is Date { + return isDate(value) && !isNan(Number(value)); +} + export function isValidLength(value: unknown): value is number { return isSafeInteger(value) && value >= 0; } @@ -917,6 +923,7 @@ type Assert = { propertyKey: (value: unknown) => asserts value is PropertyKey; formData: (value: unknown) => asserts value is FormData; urlSearchParams: (value: unknown) => asserts value is URLSearchParams; + validDate: (value: unknown) => asserts value is Date; validLength: (value: unknown) => asserts value is number; whitespaceString: (value: unknown) => asserts value is string; @@ -1022,6 +1029,7 @@ export const assert: Assert = { urlInstance: assertUrlInstance, urlSearchParams: assertUrlSearchParams, urlString: assertUrlString, + validDate: assertValidDate, validLength: assertValidLength, weakMap: assertWeakMap, weakRef: assertWeakRef, @@ -1114,6 +1122,7 @@ const methodTypeMap = { isUrlInstance: 'URL', isUrlSearchParams: 'URLSearchParams', isUrlString: 'string with a URL', + isValidDate: 'valid Date', isValidLength: 'valid length', isWeakMap: 'WeakMap', isWeakRef: 'WeakRef', @@ -1651,6 +1660,12 @@ export function assertUrlString(value: unknown): asserts value is string { } } +export function assertValidDate(value: unknown): asserts value is Date { + if (!isValidDate(value)) { + throw new TypeError(typeErrorMessage('valid Date', value)); + } +} + export function assertValidLength(value: unknown): asserts value is number { if (!isValidLength(value)) { throw new TypeError(typeErrorMessage('valid length', value)); diff --git a/test/test.ts b/test/test.ts index bbf7b57..1b94a01 100644 --- a/test/test.ts +++ b/test/test.ts @@ -2101,6 +2101,17 @@ test('is.urlSearchParams', t => { }); }); +test('is.validDate', t => { + t.true(is.validDate(new Date())); + t.false(is.validDate(new Date('x'))); + t.notThrows(() => { + assert.validDate(new Date()); + }); + t.throws(() => { + assert.validDate(new Date('x')); + }); +}); + test('is.validLength', t => { t.true(is.validLength(1)); t.true(is.validLength(0));