TypeScript provides strict types to ensure variables always hold the expected values. These basic types are essentially JavaScript primitive data types used as "rules" to dictate what a variable can contain.
Basic Types
Below is a list of the safe types used to prevent errors in your code:
| Type | Example | Description |
|---|---|---|
number | let age: number = 25; | Must be an integer or decimal value. |
string | let name: string = "Ali"; | Must be a text value. |
boolean | let isTrue: boolean = true; | Must be either true or false. |
null | let empty: null = null; | Explicitly represents "nothing." |
undefined | let x: undefined; | For uninitialized variables. |
bigint | let big: bigint = 100n; | For integers larger than the standard number type. |
symbol | let id: symbol = Symbol(); | Unique identifiers for objects. |
Type Annotations vs. Type Inference
Type Annotations
Explicitly defining what data type a variable must hold. If you attempt to assign the wrong type, TypeScript throws an error immediately.
let username: string = "Ahmed";
let age: number = 30;
Type Inference
If you do not provide an explicit type, TypeScript automatically "guesses" (infers) the type based on the value you first assigned.
let city = "Lagos"; // TypeScript infers this is a 'string'
city = 123; // ❌ Error: Type 'number' is not assignable to 'string'
Special Types
These types are used when the data type might be dynamic or unknown.
any: Allows literally any data type. Usinganyeffectively turns off TypeScript's safety features, so it is generally advisable to avoid it.unknown: Similar toanyin that you can assign any value to anunknownvariable. However, you cannot assign anunknownvariable to a typed variable without first checking and narrowing its type. This makes it the safer choice overanywhen the type is genuinely uncertain.
let randomValue: any = 10;
randomValue = "Hello"; // ✅ No error — any accepts everything
let value: unknown = "Hello";
let num: number = value; // ❌ Error: Type 'unknown' is not assignable to 'number'
// You must first check the type before assigning it
Union Types
A Union Type allows a variable to accept two or more specific types. This is useful when a value could legitimately be one of several types (e.g., an ID that could be a string or a number).
let score: number | string;
score = 100; // ✅ Allowed
score = "A+"; // ✅ Allowed
score = true; // ❌ Error: Type 'boolean' is not assignable to 'number | string'
Type Narrowing
When working with union types, you often need to narrow the type before performing specific operations like math or string manipulation. Narrowing means using a conditional check to tell TypeScript which specific type you are working with at that point in the code.
The most common way to narrow is with a typeof check inside an if statement:
let score: number | string;
score = 100;
if (typeof score === "number") {
console.log(score * 2); // ✅ Safe — TypeScript knows it's a number here
} else {
console.log(score.toUpperCase()); // ✅ Safe — TypeScript knows it's a string here
}
Without narrowing, TypeScript will not allow you to call number-only or string-only methods on a union type, because it cannot guarantee which type the variable holds at runtime.