TypeScript Basics

Easy

TypeScript adds a compile-time type system on top of JavaScript. Every valid JavaScript file is already valid TypeScript, but TypeScript lets you annotate variables, parameters, and return values so the compiler catches errors before your code ever runs. Understanding the primitive types, type annotations, and basic inference rules is the foundation for everything else in TypeScript.

Interactive Visualization

Key Points

  • TypeScript is a strict superset of JavaScript — all JS is valid TS
  • Type annotations use a colon syntax: `let name: string`
  • Primitive types include string, number, boolean, null, undefined, symbol, and bigint
  • TypeScript infers types when you assign a value, so explicit annotations are often optional
  • The `unknown` type is the type-safe counterpart of `any` — it requires narrowing before use
  • Union types (`string | number`) allow a value to be one of several types
  • Literal types (`"hello"` or `42`) restrict values to exact literals

Code Examples

Type Annotations & Inference

// Explicit annotations
let name: string = 'Alice'
let age: number = 30
let active: boolean = true

// TypeScript infers these types automatically
let city = 'London'       // inferred as string
let score = 100           // inferred as number
let items = [1, 2, 3]     // inferred as number[]

// Function with typed parameters and return
function greet(name: string, formal: boolean): string {
  return formal ? `Dear ${name}` : `Hi ${name}`
}

TypeScript can infer types from initial assignments, but explicit annotations on function parameters are required when the compiler cannot infer them from context.

Union & Literal Types

// Union type — accepts multiple types
type ID = string | number

function findUser(id: ID): void {
  if (typeof id === 'string') {
    console.log(id.toUpperCase()) // TS knows id is string here
  } else {
    console.log(id.toFixed(2))    // TS knows id is number here
  }
}

// Literal type — restricts to exact values
type Direction = 'north' | 'south' | 'east' | 'west'

function move(dir: Direction): void {
  // dir can only be one of the four strings
}

move('north') // OK
// move('up')  // Error: not assignable to Direction

Union types combine multiple types, while literal types restrict a value to specific constants. Together they model finite sets of valid values.

Interfaces vs Type Aliases

// Interface — describes object shapes, can be extended
interface User {
  name: string
  age: number
}

interface Admin extends User {
  role: 'admin'
}

// Type alias — can represent any type, including unions
type Result = { success: true; data: string } | { success: false; error: string }

// Intersection type — combine multiple types
type AdminUser = User & { role: 'admin'; permissions: string[] }

Interfaces define object contracts and support declaration merging. Type aliases are more flexible — they can represent unions, intersections, and mapped types.

Common Mistakes

  • Using `any` to silence type errors instead of properly typing the value
  • Confusing `unknown` with `any` — unknown requires narrowing, any bypasses all checks
  • Forgetting that TypeScript types are erased at runtime — they provide no runtime safety
  • Over-annotating when TypeScript can infer the type automatically
  • Using `String` (capital S object wrapper) instead of `string` (primitive type)

Interview Tips

  • Explain the difference between `any` and `unknown` — this is a classic question
  • Know when to use `interface` vs `type` — interfaces for object shapes, types for unions and complex compositions
  • Mention that TypeScript is structurally typed, not nominally typed
  • Be ready to explain type inference and when explicit annotations are needed

Related Concepts