Primitive types
What you'll learn:
- write the primitive types
number,string,boolean,bigintandsymbol; - explain why
nulldoes not fit thestringtype in strict mode; - tell
anyfromunknownand check anunknownvalue before using it; - explain what
voidandnevermean as a function's result type.

Let's go back to the customs border from the first theme. Every parcel travels with a declaration that says what is inside. The inspector compares the declaration with the contents and only then lets the parcel across the border. In TypeScript the declaration is a type, and the inspector is the compiler, tsc.
The simplest parcels carry a single value: a number, a piece of text, a "yes" or a "no". The types of such values are called primitive. You know the values themselves from JavaScript, and TypeScript adds a declaration to them:
const price: number = 199.9;
const title: string = "Kettle";
const inStock: boolean = true;
console.log(title, price, inStock); // Kettle 199.9 trueLet's walk through the example line by line:
priceis declared with the typenumber: it holds a number.titleholds a string; its type isstring.inStockholds a boolean value; its type isboolean.console.logprints all three values. The types do not affect the output:tscerases them after the check.
If you put something into the box that the declaration does not name, such as the string "yes" in inStock, the inspector stops the parcel before the program even runs.
Five primitive types
Annotations use the same words that JavaScript's typeof operator returns:
number: any number, whole or fractional, plusNaNandInfinity;string: strings;boolean: two values,trueandfalse;bigint: whole numbers of any length, written with annat the end:10n;symbol: unique values created by theSymbolfunction.
The last two types are rare in programs, but they are written the same way:
const big: bigint = 9007199254740993n;
const id: symbol = Symbol("id");
console.log(typeof big, typeof id); // bigint symboltypeof prints the same words that stand in the annotations: bigint and symbol. You cannot mix bigint and number in one expression. The compiler rejects the expression big + 1, and JavaScript would throw a TypeError on such a line.
number stores whole numbers exactly only up to 9007199254740991, and the number in the example is bigger: as a number it would round to 9007199254740992. That is what bigint is for.
One number for all numbers
In many languages whole and fractional numbers are different types: int, float, double. In TypeScript, as in JavaScript, all ordinary numbers share one type, number. A variable let count: number = 3 happily accepts 2.5 too.
TypeScript has no int type at all. The annotation let count: int = 3 gives the error Cannot find name 'int': the compiler knows no such name.
Interviewers like to ask what the basic types in TypeScript are. A good answer names the five primitives, says that one number covers all numbers, and adds null and undefined. The next section is about them.
null and undefined are separate types
In JavaScript an empty value can go into any variable. The trouble comes later: if city holds null, the line city.toUpperCase() stops the program with TypeError: Cannot read properties of null (reading 'toUpperCase').
In strict mode, which this course always has on, null and undefined have types of their own, primitive ones too, which makes seven primitive types in all. The type null has one value, null, and the type undefined also has one, undefined. They do not fit other types:
const city: string = null; // ✗error TS2322: Type 'null' is not assignable to type 'string'.A "text" declaration on an empty box is a lie, and the inspector does not let such a parcel through. In the same way, let count: number = undefined gives Type 'undefined' is not assignable to type 'number'. In return, you can trust a string variable: it always holds a string, and its methods never fail on null.
Note that typeof null gives "object" because of an old JavaScript mistake, while the TypeScript type is called null.
Here the customs picture stops working. A real inspector opens the box, while tsc sees only the code: it checks what is written in the program and never sees the values that arrive at run time.
Common mistake
The type was written with a capital letter:
function shout(text: string): string {
return text.toUpperCase();
}
const greeting: String = "Hi";
console.log(shout(greeting)); // ✗error TS2345: Argument of type 'String' is not assignable to parameter of type 'string'.
'string' is a primitive, but 'String' is a wrapper object. Prefer using 'string' when possible.String, Number and Boolean with a capital letter are the types of wrapper objects: the objects JavaScript creates with a call like new String("Hi"). TypeScript lets you write these types, but they do not fit where a string is expected. The second line of the message suggests the fix: write string in lowercase, and the call shout(greeting) passes the check.
Key points
- Primitive types are written in lowercase:
number,string,boolean,bigint,symbol, the same wordstypeofprints. numberis one type for whole and fractional numbers; TypeScript has nointorfloat.- In strict mode
nullandundefinedare separate types, andstringdoes not accept them. String,NumberandBooleanwith a capital letter are wrapper-object types; annotations never use them.