Improve is.integer & is.safeInteger TypeScript type
This commit is contained in:
parent
de50144b95
commit
d2e65aa5b8
2 changed files with 34 additions and 13 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
/// <reference lib="dom"/>
|
/// <reference lib="dom"/>
|
||||||
/// <reference types="node"/>
|
/// <reference types="node"/>
|
||||||
|
|
||||||
import {Class, TypedArray, ObservableLike, Primitive} from './types';
|
import {Class, TypedArray, ObservableLike, Primitive, Integer} from './types';
|
||||||
|
|
||||||
const typedArrayTypeNames = [
|
const typedArrayTypeNames = [
|
||||||
'Int8Array',
|
'Int8Array',
|
||||||
|
|
@ -258,8 +258,8 @@ is.nan = (value: unknown) => Number.isNaN(value as number);
|
||||||
|
|
||||||
is.primitive = (value: unknown): value is Primitive => is.null_(value) || isPrimitiveTypeName(typeof value);
|
is.primitive = (value: unknown): value is Primitive => is.null_(value) || isPrimitiveTypeName(typeof value);
|
||||||
|
|
||||||
is.integer = (value: unknown): value is number => Number.isInteger(value as number);
|
is.integer = <T extends number>(value: T): value is Integer<T> => Number.isInteger(value);
|
||||||
is.safeInteger = (value: unknown): value is number => Number.isSafeInteger(value as number);
|
is.safeInteger = <T extends number>(value: T): value is Integer<T> => Number.isSafeInteger(value);
|
||||||
|
|
||||||
is.plainObject = <Value = unknown>(value: unknown): value is Record<PropertyKey, Value> => {
|
is.plainObject = <Value = unknown>(value: unknown): value is Record<PropertyKey, Value> => {
|
||||||
// From: https://github.com/sindresorhus/is-plain-obj/blob/main/index.js
|
// From: https://github.com/sindresorhus/is-plain-obj/blob/main/index.js
|
||||||
|
|
@ -279,7 +279,7 @@ export interface ArrayLike<T> {
|
||||||
readonly length: number;
|
readonly length: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isValidLength = (value: unknown): value is number => is.safeInteger(value) && value >= 0;
|
const isValidLength = <T extends number>(value: T): value is Integer<T> => is.safeInteger(value) && value >= 0;
|
||||||
is.arrayLike = <T = unknown>(value: unknown): value is ArrayLike<T> => !is.nullOrUndefined(value) && !is.function_(value) && isValidLength((value as ArrayLike<T>).length);
|
is.arrayLike = <T = unknown>(value: unknown): value is ArrayLike<T> => !is.nullOrUndefined(value) && !is.function_(value) && isValidLength((value as ArrayLike<T>).length);
|
||||||
|
|
||||||
is.inRange = (value: number, range: number | number[]): value is number => {
|
is.inRange = (value: number, range: number | number[]): value is number => {
|
||||||
|
|
@ -336,7 +336,7 @@ is.nodeStream = (value: unknown): value is NodeStream => is.object(value) && is.
|
||||||
|
|
||||||
is.infinite = (value: unknown): value is number => value === Infinity || value === -Infinity;
|
is.infinite = (value: unknown): value is number => value === Infinity || value === -Infinity;
|
||||||
|
|
||||||
const isAbsoluteMod2 = (remainder: number) => (value: number): value is number => is.integer(value) && Math.abs(value % 2) === remainder;
|
const isAbsoluteMod2 = (remainder: number) => <T extends number>(value: T): value is Integer<T> => is.integer(value) && Math.abs(value % 2) === remainder;
|
||||||
is.evenInteger = isAbsoluteMod2(0);
|
is.evenInteger = isAbsoluteMod2(0);
|
||||||
is.oddInteger = isAbsoluteMod2(1);
|
is.oddInteger = isAbsoluteMod2(1);
|
||||||
|
|
||||||
|
|
@ -509,8 +509,8 @@ interface Assert {
|
||||||
falsy: (value: unknown) => asserts value is unknown;
|
falsy: (value: unknown) => asserts value is unknown;
|
||||||
nan: (value: unknown) => asserts value is unknown;
|
nan: (value: unknown) => asserts value is unknown;
|
||||||
primitive: (value: unknown) => asserts value is Primitive;
|
primitive: (value: unknown) => asserts value is Primitive;
|
||||||
integer: (value: unknown) => asserts value is number;
|
integer: <T extends number>(value: T) => asserts value is Integer<T>;
|
||||||
safeInteger: (value: unknown) => asserts value is number;
|
safeInteger: <T extends number>(value: T) => asserts value is Integer<T>;
|
||||||
plainObject: <Value = unknown>(value: unknown) => asserts value is Record<PropertyKey, Value>;
|
plainObject: <Value = unknown>(value: unknown) => asserts value is Record<PropertyKey, Value>;
|
||||||
typedArray: (value: unknown) => asserts value is TypedArray;
|
typedArray: (value: unknown) => asserts value is TypedArray;
|
||||||
arrayLike: <T = unknown>(value: unknown) => asserts value is ArrayLike<T>;
|
arrayLike: <T = unknown>(value: unknown) => asserts value is ArrayLike<T>;
|
||||||
|
|
@ -534,8 +534,8 @@ interface Assert {
|
||||||
urlSearchParams: (value: unknown) => asserts value is URLSearchParams;
|
urlSearchParams: (value: unknown) => asserts value is URLSearchParams;
|
||||||
|
|
||||||
// Numbers.
|
// Numbers.
|
||||||
evenInteger: (value: number) => asserts value is number;
|
evenInteger: <T extends number>(value: T) => asserts value is Integer<T>;
|
||||||
oddInteger: (value: number) => asserts value is number;
|
oddInteger: <T extends number>(value: T) => asserts value is Integer<T>;
|
||||||
|
|
||||||
// Two arguments.
|
// Two arguments.
|
||||||
directInstanceOf: <T>(instance: unknown, class_: Class<T>) => asserts instance is T;
|
directInstanceOf: <T>(instance: unknown, class_: Class<T>) => asserts instance is T;
|
||||||
|
|
@ -610,8 +610,8 @@ export const assert: Assert = {
|
||||||
falsy: (value: unknown): asserts value is unknown => assertType(is.falsy(value), AssertionTypeDescription.falsy, value),
|
falsy: (value: unknown): asserts value is unknown => assertType(is.falsy(value), AssertionTypeDescription.falsy, value),
|
||||||
nan: (value: unknown): asserts value is unknown => assertType(is.nan(value), AssertionTypeDescription.nan, value),
|
nan: (value: unknown): asserts value is unknown => assertType(is.nan(value), AssertionTypeDescription.nan, value),
|
||||||
primitive: (value: unknown): asserts value is Primitive => assertType(is.primitive(value), AssertionTypeDescription.primitive, value),
|
primitive: (value: unknown): asserts value is Primitive => assertType(is.primitive(value), AssertionTypeDescription.primitive, value),
|
||||||
integer: (value: unknown): asserts value is number => assertType(is.integer(value), AssertionTypeDescription.integer, value),
|
integer: <T extends number>(value: T): asserts value is Integer<T> => assertType(is.integer(value), AssertionTypeDescription.integer, value),
|
||||||
safeInteger: (value: unknown): asserts value is number => assertType(is.safeInteger(value), AssertionTypeDescription.safeInteger, value),
|
safeInteger: <T extends number>(value: T): asserts value is Integer<T> => assertType(is.safeInteger(value), AssertionTypeDescription.safeInteger, value),
|
||||||
plainObject: <Value = unknown>(value: unknown): asserts value is Record<PropertyKey, Value> => assertType(is.plainObject(value), AssertionTypeDescription.plainObject, value),
|
plainObject: <Value = unknown>(value: unknown): asserts value is Record<PropertyKey, Value> => assertType(is.plainObject(value), AssertionTypeDescription.plainObject, value),
|
||||||
typedArray: (value: unknown): asserts value is TypedArray => assertType(is.typedArray(value), AssertionTypeDescription.typedArray, value),
|
typedArray: (value: unknown): asserts value is TypedArray => assertType(is.typedArray(value), AssertionTypeDescription.typedArray, value),
|
||||||
arrayLike: <T = unknown>(value: unknown): asserts value is ArrayLike<T> => assertType(is.arrayLike(value), AssertionTypeDescription.arrayLike, value),
|
arrayLike: <T = unknown>(value: unknown): asserts value is ArrayLike<T> => assertType(is.arrayLike(value), AssertionTypeDescription.arrayLike, value),
|
||||||
|
|
@ -635,8 +635,8 @@ export const assert: Assert = {
|
||||||
urlSearchParams: (value: unknown): asserts value is URLSearchParams => assertType(is.urlSearchParams(value), 'URLSearchParams', value),
|
urlSearchParams: (value: unknown): asserts value is URLSearchParams => assertType(is.urlSearchParams(value), 'URLSearchParams', value),
|
||||||
|
|
||||||
// Numbers.
|
// Numbers.
|
||||||
evenInteger: (value: number): asserts value is number => assertType(is.evenInteger(value), AssertionTypeDescription.evenInteger, value),
|
evenInteger: <T extends number>(value: T): asserts value is Integer<T> => assertType(is.evenInteger(value), AssertionTypeDescription.evenInteger, value),
|
||||||
oddInteger: (value: number): asserts value is number => assertType(is.oddInteger(value), AssertionTypeDescription.oddInteger, value),
|
oddInteger: <T extends number>(value: T): asserts value is Integer<T> => assertType(is.oddInteger(value), AssertionTypeDescription.oddInteger, value),
|
||||||
|
|
||||||
// Two arguments.
|
// Two arguments.
|
||||||
directInstanceOf: <T>(instance: unknown, class_: Class<T>): asserts instance is T => assertType(is.directInstanceOf(instance, class_), AssertionTypeDescription.directInstanceOf, instance),
|
directInstanceOf: <T>(instance: unknown, class_: Class<T>): asserts instance is T => assertType(is.directInstanceOf(instance, class_), AssertionTypeDescription.directInstanceOf, instance),
|
||||||
|
|
|
||||||
|
|
@ -47,3 +47,24 @@ export interface ObservableLike {
|
||||||
subscribe(observer: (value: unknown) => void): void;
|
subscribe(observer: (value: unknown) => void): void;
|
||||||
[Symbol.observable](): ObservableLike;
|
[Symbol.observable](): ObservableLike;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
A `number` that is an integer.
|
||||||
|
You can't pass a `bigint` as they are already guaranteed to be integers.
|
||||||
|
|
||||||
|
Use-case: Validating and documenting parameters.
|
||||||
|
|
||||||
|
@example
|
||||||
|
```
|
||||||
|
import {Integer} from 'type-fest';
|
||||||
|
declare function setYear<T extends number>(length: Integer<T>): void;
|
||||||
|
```
|
||||||
|
|
||||||
|
@see NegativeInteger
|
||||||
|
@see NonNegativeInteger
|
||||||
|
|
||||||
|
@category Numeric
|
||||||
|
*/
|
||||||
|
// `${bigint}` is a type that matches a valid bigint literal without the `n` (ex. 1, 0b1, 0o1, 0x1)
|
||||||
|
// Because T is a number and not a string we can effectively use this to filter out any numbers containing decimal points
|
||||||
|
export type Integer<Type extends number> = `${Type}` extends `${bigint}` ? Type : never;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue