Number and Numeric
The number category identifies number and number literals. The numeric category widens that to
number | bigint and adds the value-shape predicates — integer, positive, negative — plus conversions
between numeric literals and strings. Both are exported from the package root, and number/number_plus.ts
re-exports the numeric set as well.
All the Is* types below accept the standard branching options (selection, distributive, $any,
$unknown, $never, $void, $then, $else). See
type branching and Options.
exact is accepted only where it has something to say: on IsNumber, IsInteger, IsPositive,
IsNegative and their negations, where it separates the wide number and bigint types from their
literals. The *Literal predicates and IsNumeric reject it, because for them it would have nothing
left to separate.
IsNumber and IsNotNumber
Section titled “IsNumber and IsNotNumber”type IsNumber<T, $O extends $StrictOptions<$O, IsNumber.$Options> = {}>type IsNotNumber<T, $O extends $StrictOptions<$O, IsNotNumber.$Options> = {}>True for number and every number literal. bigint is not a number.
type R1 = IsNumber<number> // truetype R2 = IsNumber<1> // truetype R3 = IsNumber<1n> // falsetype R4 = IsNumber<string | number> // booleanWith selection: 'filter' the matching part of the input comes back instead of a boolean:
type R1 = IsNumber<1, { selection: 'filter' }> // 1type R2 = IsNumber<string | number, { selection: 'filter' }> // numbertype R3 = IsNotNumber<string | 1, { selection: 'filter' }> // stringIsNumberLiteral and IsNotNumberLiteral
Section titled “IsNumberLiteral and IsNotNumberLiteral”type IsNumberLiteral<T, $O extends $StrictOptions<$O, IsNumberLiteral.$Options> = {}>type IsNotNumberLiteral<T, $O extends $StrictOptions<$O, IsNotNumberLiteral.$Options> = {}>Separates a literal from the wide number type.
type R1 = IsNumberLiteral<1> // truetype R2 = IsNumberLiteral<number> // falsetype R3 = IsNumberLiteral<string | 1> // booleantype R4 = IsNumberLiteral<string | 1, { distributive: false }> // falseThese already answer the literal question, so they do not take exact; passing it is a compile
error.
Numeric and Zero
Section titled “Numeric and Zero”type Numeric = number | biginttype Zero = 0 | 0nTwo aliases the numeric predicates are built on. Numeric is the union the whole category operates over;
Zero covers both zero literals.
IsNumeric and IsNotNumeric
Section titled “IsNumeric and IsNotNumeric”type IsNumeric<T, $O extends $StrictOptions<$O, IsNumeric.$Options> = {}>type IsNotNumeric<T, $O extends $StrictOptions<$O, IsNotNumeric.$Options> = {}>IsNumber widened to number | bigint.
type R1 = IsNumeric<1> // truetype R2 = IsNumeric<1n> // truetype R3 = IsNumeric<1.1> // truetype R4 = IsNumeric<'1'> // falseIsNumeric does not take exact: number | bigint has no single wide form to be exact about.
IsInteger and IsNotInteger
Section titled “IsInteger and IsNotInteger”type IsInteger<T, $O extends $StrictOptions<$O, IsInteger.$Options> = {}>type IsNotInteger<T, $O extends $StrictOptions<$O, IsNotInteger.$Options> = {}>Every bigint is an integer, so bigint itself is one. For number, the literal is inspected for a
fractional part. The wide number type resolves to boolean, because it contains both integers and
non-integers.
type R1 = IsInteger<0> // truetype R2 = IsInteger<1n> // truetype R3 = IsInteger<bigint> // truetype R4 = IsInteger<1.1> // falsetype R5 = IsInteger<number> // booleantype R6 = IsNotInteger<number> // booleanWith exact: true only the wide number and bigint match; every literal answers the $else
branch. bigint is still an integer and number still holds both, so the wide answers do not move:
type R1 = IsInteger<bigint, { exact: true }> // truetype R2 = IsInteger<number, { exact: true }> // booleantype R3 = IsInteger<1, { exact: true }> // falsetype R4 = IsInteger<1n, { exact: true }> // falsetype R5 = IsNotInteger<1, { exact: true }> // truetype R6 = IsNotInteger<bigint, { exact: true }> // falseIsPositive, IsNegative and their negations
Section titled “IsPositive, IsNegative and their negations”type IsPositive<T, $O extends $StrictOptions<$O, IsPositive.$Options> = {}>type IsNegative<T, $O extends $StrictOptions<$O, IsNegative.$Options> = {}>type IsNotPositive<T, $O extends $StrictOptions<$O, IsNotPositive.$Options> = {}>type IsNotNegative<T, $O extends $StrictOptions<$O, IsNotNegative.$Options> = {}>Sign is read off the literal, so zero is positive and non-negative.
type R1 = IsPositive<1> // truetype R2 = IsPositive<0> // truetype R3 = IsPositive<-1> // falsetype R4 = IsNegative<-1n> // truetype R5 = IsNotNegative<0> // trueThe wide number and bigint types resolve to boolean, because they stand for the union of all
positive and all negative literals and the check distributes over that union:
type R1 = IsPositive<number> // booleantype R2 = IsNegative<bigint> // booleanThe special types are not numeric, so IsPositive and IsNegative reject them and their negations
accept them:
type R1 = IsNegative<any> // falsetype R2 = IsPositive<unknown> // falsetype R3 = IsNotNegative<never> // truetype R4 = IsNotPositive<void> // trueWith exact: true only the wide number and bigint match, so every literal answers the $else
branch. The sign of a wide type is unknown, so it stays boolean:
type R1 = IsPositive<number, { exact: true }> // booleantype R2 = IsPositive<bigint, { exact: true }> // booleantype R3 = IsPositive<1, { exact: true }> // falsetype R4 = IsNegative<-1, { exact: true }> // falsetype R5 = IsNotPositive<1, { exact: true }> // truetype R6 = IsNotNegative<-1, { exact: true }> // trueThe numeric literal predicates
Section titled “The numeric literal predicates”type IsPositiveLiteral<T, $O extends $StrictOptions<$O, IsPositiveLiteral.$Options> = {}>type IsNegativeLiteral<T, $O extends $StrictOptions<$O, IsNegativeLiteral.$Options> = {}>type IsIntegerLiteral<T, $O extends $StrictOptions<$O, IsIntegerLiteral.$Options> = {}>type IsNotPositiveLiteral<T, $O extends $StrictOptions<$O, IsNotPositiveLiteral.$Options> = {}>type IsNotNegativeLiteral<T, $O extends $StrictOptions<$O, IsNotNegativeLiteral.$Options> = {}>type IsNotIntegerLiteral<T, $O extends $StrictOptions<$O, IsNotIntegerLiteral.$Options> = {}>The other half of the exact split: these match only literals, the way IsNumberLiteral does for
IsNumber. The wide number and bigint are not literals, so they never match — where
IsPositive<number> is boolean, IsPositiveLiteral<number> is false.
type R1 = IsPositiveLiteral<1> // truetype R2 = IsPositiveLiteral<1n> // truetype R3 = IsPositiveLiteral<-1> // falsetype R4 = IsPositiveLiteral<number> // falsetype R5 = IsNegativeLiteral<-1.1> // truetype R6 = IsIntegerLiteral<1n> // truetype R7 = IsIntegerLiteral<1.1> // falsetype R8 = IsIntegerLiteral<bigint> // falseEach IsNot*Literal is the negation of its positive form, so everything that is not that kind of
literal passes — the wide types, the non-numeric types and the special types included:
type R1 = IsNotPositiveLiteral<-1> // truetype R2 = IsNotPositiveLiteral<number> // truetype R3 = IsNotPositiveLiteral<string> // truetype R4 = IsNotPositiveLiteral<1> // falsetype R5 = IsNotIntegerLiteral<1.1> // truetype R6 = IsNotIntegerLiteral<1n> // falseThey do not take exact. On strings exact excludes template literal types such as ${number},
which do not reduce to a single literal; numbers have no equivalent middle case, so the option would
compile and do nothing.
StringToNumber, StringToNumeric and NumericToString
Section titled “StringToNumber, StringToNumeric and NumericToString”type StringToNumber<S extends string, $O extends $StrictOptions<$O, StringToNumber.$Options> = {}>type StringToNumeric<S extends string, $O extends $StrictOptions<$O, StringToNumeric.$Options> = {}>type NumericToString<N extends number | bigint>Conversions between numeric literal types and their string forms. StringToNumber produces a number
literal, StringToNumeric also recognises the n suffix and produces a bigint. $O['$fail'] is
returned when the string is not a numeric literal.
NumericToString casts the other way for both number and bigint, so there is no
NumberToString or BigintToString. A bigint keeps its n suffix, so the result casts back with
StringToNumeric. StringToBigint accepts only the n form.
type R1 = StringToNumber<'1'> // 1type R2 = StringToNumber<'-1'> // -1type R3 = StringToNumber<'abc'> // nevertype R4 = StringToNumber<'abc', { $fail: 'fail' }> // 'fail'
type R5 = StringToNumeric<'1n'> // 1ntype R6 = NumericToString<1.23> // '1.23'type R7 = NumericToString<-1n> // '-1n'type R8 = StringToNumeric<NumericToString<-1n>> // -1nStringToNumber also normalises redundant fractional zeroes: StringToNumber<'1.0'> is 1 and
StringToNumber<'-0'> is 0.
Namespaces
Section titled “Namespaces”NumericPlus re-exports the numeric predicates under one name, which is useful when the flat names
collide with your own:
import type { NumericPlus } from 'type-plus'
type R1 = NumericPlus.IsInteger<1n> // truetype R2 = NumericPlus.IsPositive<-1> // false🗑️ removed in 8.0.0: the NumberPlus namespace — use NumericPlus, plus the top-level IsNumber /
IsNotNumber. It held the same members as NumericPlus plus IsNumber and IsNotNumber: replace
NumberPlus.IsInteger with NumericPlus.IsInteger, and NumberPlus.IsNumber with IsNumber.
Reference
Section titled “Reference”| Type | Description |
|---|---|
IsNumber / IsNotNumber |
T is (not) number or a number literal |
IsNumberLiteral / IsNotNumberLiteral |
T is (not) a number literal |
IsNumeric / IsNotNumeric |
T is (not) number | bigint |
IsInteger / IsNotInteger |
T is (not) an integer, bigint included |
IsPositive / IsNotPositive |
T is (not) a positive numeric type, zero included |
IsNegative / IsNotNegative |
T is (not) a negative numeric type |
IsIntegerLiteral / IsNotIntegerLiteral |
T is (not) an integer literal |
IsPositiveLiteral / IsNotPositiveLiteral |
T is (not) a positive numeric literal, zero included |
IsNegativeLiteral / IsNotNegativeLiteral |
T is (not) a negative numeric literal |
Numeric |
number | bigint |
Zero |
0 | 0n |
StringToNumber<S, $O> |
string literal to number literal |
StringToNumeric<S, $O> |
string literal to number or bigint literal |
NumericToString<N> |
number or bigint literal to string literal |
For arithmetic on these literals, see Math.
Source: src/number and
src/numeric.