number
Types every JavaScript number — integers and floats alike, all IEEE 754 doubles.
let myAge: number = 42;- Added in TypeScript 1.0
Errors
Assigning a Number wrapper object to a number is a compile error: "Type 'Number' is not assignable to type 'number'."
Changelog
- PHP 2.7Numeric separators (1_000_000) are permitted in numeric literals.
- PHP 3.2bigint added as a separate primitive for integers beyond the safe range; it does not mix with number.
- PHP 4.1Template literal types allow `${number}` patterns, e.g. `${number}px`.
number is the single numeric type for ordinary JavaScript values. As the handbook puts it, JavaScript has no special runtime value for integers, so there is no int or float — 42, 3.14, 0xff, 1e3 and -0 are all number.
What the type does not tell you
Every number is an IEEE 754 double, and the type carries none of the consequences:
0.1 + 0.2is0.30000000000000004. Type-checking will not warn you; use integer minor units for money, or compare with a tolerance.- Integers are exact only up to
Number.MAX_SAFE_INTEGER(253−1). Beyond it, distinct values collapse onto each other silently. That is whatbigintis for. NaNand±Infinityare members ofnumber, so a function typed(n: number) => numbercan returnNaNwith no complaint. Validate withNumber.isFinite.
Narrowing it
Numeric literal unions (0 | 1 | 2) constrain the value to a known set, which is useful for exit codes, HTTP statuses and enum-like flags. As with string, the capitalised Number is the boxed wrapper and should never be used as an annotation.
Example
When to use it
- Annotating counts, offsets and measurements where 2^53 is comfortably out of reach
- Constraining a status or exit code with a numeric literal union such as 0 | 1 | 2
- Deciding a monetary amount should be stored as integer cents rather than a float
Frequently asked questions
Does TypeScript have separate int and float types?
No. JavaScript has one numeric representation — the IEEE 754 double — so TypeScript has one `number` type covering integers, floats, hex, and exponential literals. Use `Number.isInteger` for a runtime check, a numeric literal union to restrict the allowed values, and `bigint` when integers can exceed `Number.MAX_SAFE_INTEGER`.
When should I use bigint instead of number?
When integers can exceed 2^53−1 (`Number.MAX_SAFE_INTEGER`) and every digit matters — 64-bit database or snowflake IDs, token amounts, cryptographic values. `number` silently rounds beyond that range. `bigint` requires `target: ES2020` or higher and never mixes with `number` in arithmetic without an explicit conversion.
Why does 0.1 + 0.2 not equal 0.3 in TypeScript?
Because `number` is an IEEE 754 binary double and 0.1 and 0.2 have no exact binary representation, so the sum is `0.30000000000000004`. TypeScript does not change runtime arithmetic, so type-checking cannot catch this. Store money as integer minor units, or compare with a tolerance such as `Math.abs(a - b) < Number.EPSILON`.
More examples
Money in integer minor units
Prints `2748 $27.48`, then `27.479999999999997` and `false`. Both calculations are typed `number` and both compile, but only the integer one is exact. The alias `Cents` is documentation, not enforcement — a plain `number` still assigns to it; use a branded type if you need the compiler to keep the units apart.
type Cents = number; // an alias documents intent; it does not add checking
const prices: Cents[] = [1999, 499, 250];
const totalCents = prices.reduce((a, b) => a + b, 0);
function format(cents: Cents): string {
const sign = cents < 0 ? "-" : "";
const abs = Math.abs(cents);
return `${sign}$${Math.floor(abs / 100)}.${String(abs % 100).padStart(2, "0")}`;
}
console.log(totalCents, format(totalCents));
// The same sum in floats:
const floats = [19.99, 4.99, 2.5];
console.log(floats.reduce((a, b) => a + b, 0));
console.log(floats.reduce((a, b) => a + b, 0) === 27.48);Numeric literal unions and validation
Prints `[ 'success', 'general error', 'misuse', 'interrupted' ]` then `8080 null null null`. The literal union makes the `switch` exhaustive without a `default`, so tsc can prove a `string` is always returned. `parsePort` shows why the `number` type alone is not validation: `Number("abc")` is `NaN` and `Number("")` is `0`, both perfectly valid `number` values.
type ExitCode = 0 | 1 | 2 | 130;
function describe(code: ExitCode): string {
switch (code) {
case 0: return "success";
case 1: return "general error";
case 2: return "misuse";
case 130: return "interrupted";
}
}
function parsePort(raw: string): number | null {
const n = Number(raw);
// Number("") is 0 and Number("abc") is NaN — both need catching
if (!Number.isInteger(n) || n <= 0 || n > 65535) return null;
return n;
}
console.log([0, 1, 2, 130].map((c) => describe(c as ExitCode)));
console.log(parsePort("8080"), parsePort("abc"), parsePort(""), parsePort("99999"));
// describe(3) // Error: Argument of type '3' is not assignable to 'ExitCode'.
Discussion