Skip to content
beginner Phase 1 · TypeScript Fundamentals

Primitive Types

Use string, number, boolean, null, undefined, and symbol types.

45m
0 problems
Topic Progress 0%

Primitive Types

Primitive Types

TypeScript has primitive types that map to JavaScript runtime types.

Number, String, Boolean

let age: number = 28;
let score: number = 99.5;
let hex: number = 0xff;
let big: number = 1_000_000;

let name: string = 'Alice';
let greeting: string = `Hello, ${name}`;

let isActive: boolean = true;

Null and Undefined

let nothing: undefined = undefined;
let empty: null = null;

// With strictNullChecks, these are distinct types
function greet(name: string | null): string {
  if (name === null) return 'Hello, stranger!';
  return `Hello, ${name}!`;
}

interface Config {
  timeout?: number; // number | undefined
}

Void

function logMessage(msg: string): void {
  console.log(msg);
}
const doNothing: void = undefined;

Special Types

Special Types: any, unknown, never

any

Disables type checking entirely. Use as a last resort.

let dangerous: any = 'hello';
dangerous = 42;
dangerous.nonExistentMethod(); // runtime crash
let result: string = dangerous; // no compile error

unknown

Safest alternative to any. Must narrow before using.

let data: unknown = fetchFromAPI();

if (typeof data === 'string') {
  console.log(data.toUpperCase()); // safe
}

let str: string = data; // Error: cannot assign unknown to string

never

Represents impossible values or functions that never return.

function throwError(msg: string): never {
  throw new Error(msg);
}

type Shape = 'circle' | 'square' | 'triangle';

function getArea(shape: Shape): number {
  switch (shape) {
    case 'circle': return Math.PI * 100;
    case 'square': return 100;
    case 'triangle': return 50;
    default:
      const _exhaustive: never = shape;
      return _exhaustive;
  }
}

Annotations vs Inference

Type Annotations vs Inference

TypeScript can infer types automatically.

When Inference Works

let x = 10;                    // inferred: number
let name = 'Alice';            // inferred: string
let nums = [1, 2, 3];          // inferred: number[]
let person = { name: 'Bob', age: 30 }; // inferred object
const double = (x: number) => x * 2;   // inferred return type

When to Add Annotations

// Return type helps catch accidental changes
function calculateTotal(items: number[]): number {
  return items.reduce((sum, n) => sum + n, 0);
}

// Variables declared without initialization
let result: string;
if (condition) { result = 'yes'; }
else { result = 'no'; }

Const Assertions

let direction = 'up';           // type: string
const dir2 = 'up' as const;    // type: 'up' literal

direction = 'down';  // OK
// dir2 = 'down';   // Error

const point = [10, 20] as const; // readonly [10, 20]

Type Assertions

let input = document.getElementById('name') as HTMLInputElement;
input.value = 'Alice';

Literal Types and BigInt

Literal Types and BigInt

Literal Types

type Direction = 'up' | 'down' | 'left' | 'right';
let move: Direction = 'up';
// move = 'forward'; // Error

type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6;
let roll: DiceRoll = 3;

type Success = { ok: true; data: string };
type Failure = { ok: false; error: string };
type Result = Success | Failure;

function handleResult(result: Result) {
  if (result.ok) {
    console.log(result.data);
  } else {
    console.log(result.error);
  }
}

BigInt

let huge: bigint = 9007199254740991n;
let alsoHuge: bigint = BigInt(9007199254740991);

// BigInt cannot be mixed with number
// let mixed = huge + 1; // Error
let result = huge + 1n; // OK

Symbol

const sym1 = Symbol('id');
const sym2 = Symbol('id');
sym1 === sym2; // false - each Symbol is unique

// Useful as unique object keys
const SECRET = Symbol('secret');
const obj = {
  [SECRET]: 'hidden value',
  public: 'visible'
};

Best Practices

  • Use unknown instead of any for flexible but safe types
  • Prefer type inference when the type is obvious
  • Add explicit annotations for public API return types
  • Use literal types for finite sets of values