Chapter 1.3☕ 12 min read

Primitive Types

Everything complex is built from these 3 simple blocks.

01The 3 Building Blocks

Think about Hyderabadi biryani. What are the three absolute essentials? Rice, meat, and salt. Without rice, there's no biryani — it's just curry. Without meat, it's a plain pulao. Without salt, it's tasteless. Every other ingredient — saffron, fried onions, mint, dum — builds on top of these three foundations.

TypeScript works exactly the same way. The three essential building blocks — the primitives — are string, number, and boolean. Every complex type you'll ever write in TypeScript, whether it's an object, an array, a union, a generic, or a mapped type, is ultimately constructed from these three primitives. They are the atoms of your type system.

A string holds text — names, emails, URLs, error messages, anything with quotes around it. A number holds any numeric value — age, price, temperature, coordinates. A boolean holds exactly two values: true or false — is the user logged in? Is the item in stock? Is the feature enabled?

These three types are called primitives because they are the simplest, most fundamental data types. They cannot be broken down into smaller parts. A string is a string. A number is a number. A boolean is a boolean. You can't slice them further. Everything else in TypeScript — arrays, objects, tuples, enums — is a composite built from these primitive building blocks. Master these three, and half of TypeScript is already in your pocket.

02string, number, boolean Syntax

Let's learn the syntax for declaring variables with primitive types. In TypeScript, you use a colon (:) after the variable name to specify its type:

let name: string = "Hyderabad";
let age: number = 25;
let isDeveloper: boolean = true;

The pattern is always the same: let variableName: type = value. Think of the colon as a label — you're attaching a type tag to the variable that says "this variable will ONLY hold this kind of data." Once you tag a variable as : string, TypeScript will fight you if you try to put a number inside it.

Here are more examples with each primitive:

// string — anything in quotes
let city: string = "Charminar";
let email: string = "bhai@devinhyd.com";
let empty: string = "";  // empty string is still a valid string

// number — integers, decimals, negatives, zero
let population: number = 6800000;
let temperature: number = 38.5;
let balance: number = -500;
let zero: number = 0;

// boolean — only true or false, nothing else
let isLoggedIn: boolean = true;
let hasSubscription: boolean = false;

Notice that string values always go in quotes (single, double, or backticks), number values are written as bare digits (no quotes!), and boolean values are the reserved words true or false (also no quotes). If you write true in quotes as "true", that's a string, not a boolean — TypeScript treats them completely differently.

Once you assign a type, TypeScript enforces it strictly. If you declare let age: number = 25, you cannot later do age = "twenty-five" — TypeScript will throw an error immediately at compile time, before the code ever runs. This is the entire point of TypeScript: catching type mismatches early, when they're easy to fix, rather than at runtime when they cause mysterious bugs.

03Deep Dive — No int/float, Just number

If you're coming from Java, C++, or C#, you might be looking for int, float, double, long, or short. They don't exist in TypeScript. JavaScript has only one number type — number — and TypeScript inherits this. All of the following are the same type:

let integer: number = 42;
let decimal: number = 3.14;
let negative: number = -100;
let hex: number = 0xff;      // hexadecimal
let binary: number = 0b1010; // binary
let octal: number = 0o744;   // octal
let notANum: number = NaN;    // yes, NaN is type number
let infinity: number = Infinity; // this too!

Every single one of these is just number. Under the hood, JavaScript uses IEEE 754 double-precision 64-bit floating point for all numbers, so there's no separate integer type at the language level. This simplifies things enormously — you never have to worry about whether to use int vs float vs double.

But what about truly massive numbers? If you need numbers larger than Number.MAX_SAFE_INTEGER (which is 9,007,199,254,740,991 — about 9 quadrillion), you use bigint:

let hugeNumber: bigint = 9007199254740991n;
let anotherBig: bigint = BigInt("90071992547409912345");

Notice the n suffix — that's what makes a number literal a bigint. You can also use the BigInt() function. But remember: bigint and number cannot be mixed in arithmetic — 42n + 1 is a type error.

Two more primitives worth knowing: symbol and the difference between undefined vs null.

// symbol — creates a globally unique identifier
let id1: symbol = Symbol("key");
let id2: symbol = Symbol("key");
// id1 !== id2 — every Symbol() call creates a unique value!

// undefined — variable declared but no value assigned yet
let notAssigned: undefined = undefined;

// null — intentionally empty, "nothing here on purpose"
let emptySlot: null = null;

undefined means "this variable exists but has no value yet" — it's the default for uninitialized variables. null means "this variable intentionally has no value" — you explicitly set it to nothing. In practice, you rarely declare variables with type undefined or null directly. Instead, you use them in union types like string | null — but that's a later chapter.

04The Trap — String vs string

Here's the trap that catches almost every developer at least once: using String (capital S) instead of string (lowercase s). They look almost identical, but they are completely different things in TypeScript.

// ❌ WRONG — capital S, N, B
let name: String = "Hyderabad";
let age: Number = 25;
let active: Boolean = true;

// ✅ CORRECT — lowercase s, n, b
let name: string = "Hyderabad";
let age: number = 25;
let active: boolean = true;

Why does this matter? string (lowercase) is the primitive type — it's the keyword built into TypeScript. String (capital) is the JavaScript wrapper object — it's a constructor function that creates a String object, not a primitive string. These are fundamentally different:

typeof "hello"       // "string"  — primitive
typeof new String("hello")  // "object"  — wrapper object

"hello" === new String("hello")  // false! Different types!

The TypeScript team themselves explicitly warn against using the capital-letter versions. The official TypeScript handbook says: "Don't ever use the types Number, String, Boolean, Symbol, or Object." Always use the lowercase primitives: number, string, boolean, symbol, object.

The second trap involves null. Consider this code:

let username: string = null;  // Error with strictNullChecks on!

With strictNullChecks enabled in your tsconfig.json (which is included when you set strict: true), TypeScript will NOT let you assign null to a string variable. This is intentional and brilliant — it prevents the most common bug in JavaScript: calling .toUpperCase() on a variable that's actually null, which crashes your app at runtime.

If you genuinely need a variable that can be a string OR null, you use a union type:

let username: string | null = null;  // ✅ Explicitly allows both
username = "Bhai";                    // ✅ Also fine

This forces you to handle the null case explicitly, making your code safer. We'll cover union types in detail in a later chapter, but for now: never assign null to a primitive type variable unless you declare it with | null in the type annotation.

05Primitive Types Cheatsheet

Here's your complete cheatsheet for TypeScript primitive types. Keep this handy — you'll reference it constantly:

// ═══════ THE BIG 3 — Used 99% of the time ═══════

let name: string = "Hyderabad";    // Text, always in quotes
let age: number = 25;              // Any number — int, float, negative
let isDev: boolean = true;         // Only true or false

// ═══════ THE EXTRA 3 — For special cases ═══════

let bigValue: bigint = 9007199254740991n;  // Huge numbers (n suffix)
let uniqueId: symbol = Symbol("id");       // Globally unique identifier
let nothing: undefined = undefined;        // Declared but no value
let empty: null = null;                    // Intentionally empty

// ═══════ UNION TYPES — When a value can be two types ═══════

let nickname: string | null = null;        // Can be string OR null
let score: number | undefined = undefined; // Can be number OR undefined

The golden rules to remember forever:

  • Always lowercase: string, number, boolean — never String, Number, Boolean.
  • No int/float: Just number. It handles everything numeric.
  • Quotes matter: "true" is a string, true is a boolean. "42" is a string, 42 is a number.
  • null needs permission: With strict mode, you can't assign null to string, number, or boolean. Use string | null instead.
  • bigint is separate: Don't mix bigint and number in math operations — 42n + 1 is an error.

These 6 primitive types — string, number, boolean, bigint, symbol, and the two unit types null and undefined — are the foundation of everything in TypeScript. Every object property, every function parameter, every return type ultimately boils down to these primitives. Nail these, and the rest of TypeScript becomes infinitely easier.

Key Takeaways

  • TypeScript has 3 main primitive types: string (text), number (all numbers), and boolean (true/false).
  • Always use lowercase: string, number, boolean — never String, Number, Boolean (those are wrapper objects).
  • TypeScript has no int/float distinction — number covers integers, decimals, negatives, and even NaN and Infinity.
  • Extra primitives: bigint for huge numbers, symbol for unique IDs, undefined (not assigned), null (intentionally empty).
  • With strictNullChecks on, you cannot assign null or undefined to a string, number, or boolean variable.
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase