Basic Types: The Foundation of Type Safety

Basic Types: The Foundation of Type Safety

TypeScript's power lies in its ability to explicitly define what kind of data a variable should hold. While JavaScript has dynamic types, TypeScript provides a robust set of types that cover every scenario in modern programming.


1. Primitive Types

The most fundamental types in TypeScript are the same ones you find in JavaScript, but with strict enforcement.

  • string: Represents text data. Can use single quotes, double quotes, or backticks (template literals).
  • number: Represents all numeric values (integers and floating-point). TypeScript also supports binary, octal, and hexadecimal literals.
  • boolean: Represents a simple true or false value.
  • bigint: Used for very large integers (ES2020+).
  • symbol: Used to create unique identifiers.
let brand: string = "Nandhoo Learning";
let year: number = 2024;
let isActive: boolean = true;
let bigValue: bigint = 9007199254740991n;

2. Specialized System Types

TypeScript introduces several types that help manage the "logic" of your code.

The unknown Type (Recommended over any)

unknown is the type-safe counterpart of any. You can assign anything to unknown, but you cannot use it until you verify what it is (type narrowing).

let value: unknown = "Hello";
// console.log(value.length); // Error! We don't know if it's a string yet.

if (typeof value === "string") {
    console.log(value.length); // OK! Now TypeScript knows it's a string.
}

The any Type (Use with Caution)

Assigning a variable the any type effectively turns off TypeScript for that variable. It is useful for migrating old JavaScript projects, but it should be avoided in professional TypeScript code as it reintroduces runtime bugs.

The void Type

Used primarily as the return type of functions that do not return a value.

function logError(msg: string): void {
    console.error(msg);
}

The never Type

Represents values that never occur. For example, a function that always throws an error or has an infinite loop returns never.

function throwFatalError(): never {
    throw new Error("System Crash");
}

3. Arrays and Tuples

Arrays

You can define an array of a specific type using either type[] or Array<type>.

let scores: number[] = [10, 20, 30];
let names: Array<string> = ["Alice", "Bob"];

Tuples

A tuple allows you to express an array with a fixed number of elements where the types are known but not necessarily the same.

let person: [string, number];
person = ["Alice", 25]; // OK
// person = [25, "Alice"]; // Error: Types must match the order.

4. Enums: Named Constants

Enums allow you to define a set of named constants, making your code more readable.

Numeric Enums

enum UserRole {
    Admin = 1,
    Editor,   // Automatically 2
    Viewer    // Automatically 3
}

String Enums

enum Direction {
    Up = "UP",
    Down = "DOWN",
    Left = "LEFT",
    Right = "RIGHT"
}

5. Type Inference vs. Type Annotation

In TypeScript, you don't always have to write the type. If you assign a value immediately, TypeScript will infer the type for you.

let message = "Hello"; // TypeScript infers this is a 'string'
// message = 10; // Error! Type 'number' is not assignable to 'string'.

Professional Advice: Use Type Inference for simple variable assignments to keep code clean, and use Type Annotation for function parameters and complex return values.


6. Null and Undefined

By default, null and undefined are subtypes of all other types. However, when you enable the --strictNullChecks flag (highly recommended), you must explicitly allow them using Union Types.

let username: string | null = null;
username = "CoderKid";