HomeBytesheetsRoadmapsUI TemplatesUI ToolsStack Discussion
76 Topics
Chapter•600 Minutes

Complete TypeScript Interview Questions & Answer Bank

75+ curated TypeScript interview questions covering core type primitives, structural typing, generics, utility types, mapped types, advanced type inference, decorators, and compiler optimization.

Q1: What is TypeScript and what are its core advantages over plain JavaScript?

Difficulty:EasyTopic:Fundamentals

TypeScript is a strongly typed, open-source programming language developed by Microsoft that builds on JavaScript by adding syntactical type declarations.

Core Advantages

  • Static Type Checking: Catches errors at compile time rather than runtime.
  • Enhanced IDE Support: Enables intelligent autocompletion, refactoring, and code navigation.
  • Downlevel Compilation: Transpiles modern ECMAScript features down to older ES versions (ES5/ES3).
  • Explicit Self-Documenting Code: Interfaces and type aliases act as living documentation.
Key Takeaways
  • TypeScript is a strict syntactical superset of JavaScript.
  • All valid JavaScript code is valid TypeScript code.

Q2: What is Structural Typing (Duck Typing) and how does it differ from Nominal Typing?

Difficulty:EasyTopic:Type System

TypeScript uses a Structural Type System. Types are evaluated solely by their shape or structure (the properties and methods they possess), rather than their explicit declaration name or inheritance chain.

In Nominal Type Systems (like Java or C#), two objects with identical properties are not interchangeable unless they explicitly inherit from the same named class or interface.

Structural Compatibility Example
interface Point2D { x: number; y: number; }
interface Vector2D { x: number; y: number; }

const logPoint = (p: Point2D) => console.log(`${p.x}, ${p.y}`);
const velocity: Vector2D = { x: 10, y: 20 };

logPoint(velocity); // Valid! Vector2D matches the structure of Point2D.
💡 Even though velocity is typed as Vector2D, TypeScript accepts it because its internal structure matches Point2D.
Key Takeaways
  • TypeScript checks structure, not explicit declaration names.
  • If an object has the required fields with matching types, TypeScript considers it compatible.

Q3: What are the primitive types available in TypeScript?

Difficulty:EasyTopic:Primitives

TypeScript supports all native JavaScript primitives alongside type additions:

  • string: Textual data.
  • number: Floating-point numbers and integers.
  • boolean: True/false values.
  • bigint: Large integers beyond $2^{53} - 1$.
  • symbol: Unique, immutable identifiers.
  • null & undefined: Absence of value or uninitialized state.
  • void: Signals absence of return value from functions.
Key Takeaways
  • Primitive types in TypeScript correspond directly to JavaScript's runtime primitive types.
  • Always use lowercase primitive names (string, number) rather than wrapper objects (String, Number).

Q4: What is the difference between `any` and `unknown` types?

Difficulty:EasyTopic:Type Safety

any disables type checking entirely, turning off compile-time safety. You can access arbitrary properties, call them as functions, or assign them to any target type.

unknown is the type-safe counterpart of any. It represents any value, but TypeScript prevents you from performing arbitrary operations on an unknown variable until you perform explicit type checking or narrowing.

any vs unknown Behavior
let valueAny: any = "hello";
valueAny.foo.bar(); // Compiles fine, runtime crash!

let valueUnknown: unknown = "hello";
// valueUnknown.trim(); // Error: Object is of type 'unknown'.

if (typeof valueUnknown === "string") {
  console.log(valueUnknown.trim()); // Valid! Narrowed safely.
}
💡 unknown forces developer verification before property access, preventing accidental runtime exceptions.
Key Takeaways
  • Prefer unknown over any when working with dynamic or unexpected values.
  • unknown requires explicit narrowing before property access.

Q5: What is the `never` type and how is it used for exhaustive type checking?

Difficulty:MediumTopic:Advanced Types

The never type represents values that never occur. It represents the return type of functions that never finish (e.g., throwing an error or running an infinite loop).

Because never is a assignable to every type, but no type is assignable to never (except never itself), it is used to perform Exhaustive Type Checking inside switch statements.

Exhaustive Switch-Case Checking
type Shape = { kind: 'circle' } | { kind: 'square' };

function getArea(s: Shape): number {
  switch (s.kind) {
    case 'circle': return Math.PI * 2;
    case 'square': return 4;
    default:
      const _exhaustiveCheck: never = s;
      return _exhaustiveCheck;
  }
}
💡 If a developer adds a new union member to Shape without handling it in the switch statement, TypeScript raises a compile-time error.
Key Takeaways
  • never signals unreachable code paths.
  • Assigning unhandled union cases to never guarantees total compile-time switch coverage.

Q6: What is the difference between `type` aliases and `interface` declarations?

Difficulty:EasyTopic:Core Concepts

Both type and interface define structural contracts, but they differ in capabilities:

Interface vs Type Alias Comparison
Declaration Merging: Supported by `interface` | Unsupported by `type`
Multiple interface declarations with the same name automatically merge properties.
Union & Primitives: Unsupported by `interface` | Supported by `type`
Type aliases can define unions (A | B), primitives, tuples, and mapped types directly.
Extensibility: `extends` keyword vs Intersection (`&`)
Interfaces extend other interfaces; types create intersections.
Key Takeaways
  • Use interface for public API contracts and object structures that benefit from declaration merging.
  • Use type for union types, tuples, primitives, and complex mapped/conditional types.

Q7: What is the difference between Union Types (`|`) and Intersection Types (`&`)?

Difficulty:EasyTopic:Type Combinations
  • Union Type (A | B): Represents a value that can be either type A or type B. You can only access properties common to both types unless narrowed.
  • Intersection Type (A & B): Combines multiple type structures into one. The resulting value must satisfy both type contracts simultaneously.
Union vs Intersection
type Admin = { name: string; permissions: string[] };
type User = { name: string; email: string };

// Union: Must be Admin OR User
type Account = Admin | User;

// Intersection: Must have ALL properties from Admin AND User
type SuperAdmin = Admin & User;
💡 Intersection types merge structural constraints, requiring all combined properties.
Key Takeaways
  • Unions allow one of several types; Intersections merge multiple types into one.

Q8: What are Literal Types and how do `as const` assertions work?

Difficulty:MediumTopic:Literals

Literal types restrict variables to exact concrete values (strings, numbers, or booleans) rather than wider primitive categories.

A const assertion (as const) instructs TypeScript to infer the narrowest possible literal types for object properties and arrays, turning properties into readonly fields.

as const Assertion
// Standard object inference
const config = {
  endpoint: "/api",
  retries: 3
}; // Type: { endpoint: string; retries: number; }

// const assertion
const constConfig = {
  endpoint: "/api",
  retries: 3
} as const; // Type: { readonly endpoint: "/api"; readonly retries: 3; }
💡 as const prevents property widening and marks array/object members read-only.
Key Takeaways
  • Literal types lock values to exact concrete constants.
  • as const creates deeply immutable readonly literal data types.

Q9: What are Tuple Types in TypeScript and how do Readonly Tuples work?

Difficulty:EasyTopic:Data Structures

A Tuple is a fixed-length array where every element index has an explicitly declared type.

Standard tuples permit mutable array operations like .push(), which can bypass tuple index checks. Wrapping tuples with readonly enforces strict immutability.

Tuple and Readonly Tuple
type ResponseState = [code: number, message: string];
const state: ResponseState = [200, "OK"];

type ImmutableState = readonly [number, string];
const fixed: ImmutableState = [404, "Not Found"];
// fixed.push("error"); // Error: Property 'push' does not exist on type 'readonly [number, string]'
💡 Readonly tuples block array mutation methods like push, pop, or index modification.
Key Takeaways
  • Tuples lock array element types to explicit index positions.
  • Use readonly on tuples to block accidental array mutations.

Q10: What are Enums, String Enums, and `const enum` declarations?

Difficulty:MediumTopic:Enums

Enums allow defining named sets of constants. TypeScript supports Numeric, String, and const enums.

Standard enums generate runtime JavaScript objects. A const enum is completely removed during compilation—its values are directly inlined into call sites, leaving zero JavaScript runtime object footprint.

const enum Inlining
const enum Direction {
  Up = "UP",
  Down = "DOWN"
}

const move = Direction.Up;
// Compiled JS output:
// var move = "UP"; // No Enum object generated!
💡 const enum inlines literal values directly at compile time, reducing JavaScript bundle size.
Key Takeaways
  • Use const enum to eliminate runtime JavaScript object overhead.
  • String enums offer better readability during debugging than numeric enums.