codejump

Interview questionsTypeScript

TypeScript interview questions and answers

30 TypeScript questions picked from Codejump's quizzes, from the basics a junior is expected to know to the details that trip up senior candidates. Each one comes with its answer and an explanation — try to answer before you open it.

Junior level TypeScript questions

  1. 1.What does A & B mean when both have a property with the same name?

    javascript
    type A = { x: string; y: number };
    type B = { y: string; z: boolean };
    
    type AB = A & B;
    // AB.y = ?
    • A.AB.y = string & number = never — impossible type (string AND number simultaneously)
    • B.AB.y = string | number — union of both
    • C.AB.y = string — B wins because it's listed second
    • D.AB.y = number — A wins because it's listed first
    Show answer

    Answer: A. AB.y = string & number = never — impossible type (string AND number simultaneously)

    In an intersection A & B, a property must satisfy BOTH constraints simultaneously. y must be both string AND number:

    From the quiz Union & Intersection Types

  2. 2.What is the purpose of these compiler options?

    javascript
    {
      "compilerOptions": {
        "rootDir": "./src",
        "outDir": "./dist",
        "declaration": true
      }
    }
    • A.rootDir is where node_modules are installed; outDir is the TypeScript cache
    • B.rootDir is the source root; outDir is the compiled output directory; mirror structure is preserved
    • C.Both are optional with no default behavior
    • D.outDir is only needed for JavaScript projects
    Show answer

    Answer: B. rootDir is the source root; outDir is the compiled output directory; mirror structure is preserved

    rootDir defines the common root for source files — it controls how paths are mirrored in outDir.

    From the quiz tsconfig & Modules

  3. 3.What error does this generate?

    javascript
    function getLength<T>(value: T): number {
      return value.length; // ❌ ?
    }
    • A.No error — all types have .length
    • B.No error — TypeScript infers T must have .length
    • C.Error — generic functions can't access properties
    • D.Error — TypeScript can't guarantee T has a .length property
    Show answer

    Answer: D. Error — TypeScript can't guarantee T has a .length property

    Without a constraint, T can be any type — including number, boolean, or {} which don't have .length. TypeScript raises an error:

    From the quiz Generic Basics

  4. 4.What is the difference between public, private, and protected?

    javascript
    class BankAccount {
      public owner: string;
      private balance: number;
      protected accountNumber: string;
    
      constructor(owner: string, balance: number, number: string) {
        this.owner = owner;
        this.balance = balance;
        this.accountNumber = number;
      }
    }
    • A.All three are identical in TypeScript — access modifiers are just documentation hints
    • B.private — accessible outside the class; public — accessible only inside
    • C.public — accessible everywhere; private — accessible only inside the class; protected — accessible inside the class and subclasses
    • D.protected — prevents inheritance; private — allows inheritance
    Show answer

    Answer: C. public — accessible everywhere; private — accessible only inside the class; protected — accessible inside the class and subclasses

    | Modifier | Inside class | Subclass | Outside class | |---|---|---|---| | public | ✅ | ✅ | ✅ | | protected | ✅ | ✅ | ❌ | | private | ✅ | ❌ | ❌ |

    From the quiz Classes & Interfaces

  5. 5.What does the | operator create in TypeScript?

    javascript
    function formatId(id: string | number): string {
      return `ID: ${id}`;
    }
    • A.A bitwise OR operation on two types
    • B.An intersection type — the parameter must be both string AND number
    • C.A union type — the parameter can be either string OR number
    • D.A nullable type — equivalent to string | null
    Show answer

    Answer: C. A union type — the parameter can be either string OR number

    The | operator creates a union type — a value that can be one of several types: The function formatId accepts both strings and numbers, and TypeScript checks that only valid types are passed.

    From the quiz Type System Basics

  6. 6.Given this interface, which object assignment will TypeScript reject?

    javascript
    interface User {
      name: string;
      age: number;
    }
    • A.const u: User = { name: "Alice", age: 30 }
    • B.const u: User = { name: "Bob", age: 25, city: "Paris" }
    • C.const u: User = { name: "Charlie" }
    • D.const u: User = { name: "Diana", age: 0 }
    Show answer

    Answer: C. const u: User = { name: "Charlie" }

    An interface defines the required shape of an object. Every required property must be present. Option B is valid in a variable assignment context — TypeScript performs structural typing and accepts extra properties when assigning via a variable (though object literals passed directly to functions trigger excess property checks).

    From the quiz TypeScript Fundamentals

  7. 7.What is a discriminant property?

    javascript
    type Circle    = { kind: 'circle';    radius: number };
    type Rectangle = { kind: 'rectangle'; width: number; height: number };
    type Triangle  = { kind: 'triangle';  base: number; height: number };
    
    type Shape = Circle | Rectangle | Triangle;
    
    function area(shape: Shape): number {
      switch (shape.kind) {
        case 'circle':    return Math.PI * shape.radius ** 2;
        case 'rectangle': return shape.width * shape.height;
        case 'triangle':  return 0.5 * shape.base * shape.height;
      }
    }
    • A.kind is the discriminant — a literal-typed property shared by all union members that TypeScript uses to narrow to the correct member
    • B.kind is any property shared by all union members
    • C.TypeScript uses the property names (like radius, width) to narrow
    • D.kind is a reserved keyword in TypeScript
    Show answer

    Answer: A. kind is the discriminant — a literal-typed property shared by all union members that TypeScript uses to narrow to the correct member

    The discriminant is a property with a literal type ('circle', 'rectangle', 'triangle') that:
    • Is present in ALL union members
    • Has a different literal value in each member TypeScript uses it to narrow the union:

    From the quiz Union & Intersection Types

  8. 8.What does noImplicitAny prevent?

    javascript
    // With noImplicitAny: true
    
    function process(data) {     // (A) ?
      return data.length;
    }
    
    const items = [];             // (B) ?
    
    function identity<T>(x: T) { // (C) ?
      return x;
    }
    • A.All three cause errors — all types must be explicit
    • B.None cause errors — TypeScript infers types automatically
    • C.Only (A) causes an error
    • D.(A) and (B) cause errors — parameters and variables without type inference; (C) is fine because T is inferred
    Show answer

    Answer: D. (A) and (B) cause errors — parameters and variables without type inference; (C) is fine because T is inferred

    noImplicitAny errors when TypeScript can't infer a type and would default to any:

    From the quiz tsconfig & Modules

  9. 9.What is T when calling container() with no type argument?

    javascript
    function container<T = string>(value?: T): T | undefined {
      return value;
    }
    
    const a = container();         // T = ?
    const b = container("hello"); // T = ?
    const c = container(42);      // T = ?
    • A.a: string | undefined, b: string | undefined, c: number | undefined
    • B.a: unknown, b: string, c: number
    • C.a: string, b: string, c: string — default forces all to string
    • D.All are any
    Show answer

    Answer: A. a: string | undefined, b: string | undefined, c: number | undefined

    Default type parameters apply when the type can't be inferred:
    • container() → no argument, no inference → T defaults to string → returns string | undefined
    • container("hello") → T inferred as string → returns string | undefined
    • container(42) → T inferred as number → returns number | undefined

    From the quiz Generic Basics

  10. 10.What does this TypeScript shorthand do?

    javascript
    class Point {
      constructor(
        public x: number,
        public y: number
      ) {}
    }
    • A.x and y are only available inside the constructor
    • B.This syntax is only valid for readonly properties
    • C.public in constructor parameters creates global variables
    • D.It's shorthand for declaring x and y as class properties AND assigning them in the constructor — equivalent to 6 lines of manual code
    Show answer

    Answer: D. It's shorthand for declaring x and y as class properties AND assigning them in the constructor — equivalent to 6 lines of manual code

    Constructor parameter shorthand (parameter properties) auto-declares class properties and assigns them:

    From the quiz Classes & Interfaces

Mid level TypeScript questions

  1. 11.What do -? and +? do in mapped types?

    javascript
    type Required<T> = { [K in keyof T]-?: T[K] };
    type Optional<T> = { [K in keyof T]+?: T[K] };
    
    interface Config {
      host?: string;
      port?: number;
      debug?: boolean;
    }
    
    type StrictConfig = Required<Config>;
    type FlexConfig   = Optional<Config>; // same as Config in this case
    • A.-? removes undefined from value types; +? adds it
    • B.-? removes the optional modifier; +? adds the optional modifier
    • C.+ and - are operators on boolean types only
    • D.These modifiers only work on readonly, not ?
    Show answer

    Answer: B. -? removes the optional modifier; +? adds the optional modifier

    Mapped type modifiers control the ? (optional) and readonly flags: The built-in Required<T> uses exactly -?:

    From the quiz Template Literals & Inference

  2. 12.Why might a project require isolatedModules: true?

    javascript
    // tsconfig: "isolatedModules": true
    
    // File 1 — const enum:
    export const enum Direction { Up, Down, Left, Right }
    
    // File 2 — using it:
    import { Direction } from './file1';
    const d = Direction.Up; // ?
    • A.Error — const enum is forbidden with isolatedModules because transpilers (Babel, esbuild) process one file at a time and can't inline const enum values
    • B.isolatedModules has no effect on const enum
    • C.const enum is automatically converted to a regular enum
    • D.Works fine — isolatedModules only affects type-only imports
    Show answer

    Answer: A. Error — const enum is forbidden with isolatedModules because transpilers (Babel, esbuild) process one file at a time and can't inline const enum values

    isolatedModules: true mirrors how Babel and esbuild work — they transpile each file independently without cross-file type information: Use isolatedModules when your build tool is Babel, esbuild, or SWC — it catches patterns that break single-file transpilation.

    From the quiz Decorators & Project Setup

  3. 13.What does ReturnType extract?

    javascript
    async function fetchUser(id: string): Promise<{ id: string; name: string }> {
      // ...
      return { id, name: "Alice" };
    }
    
    type FetchUserResult = ReturnType<typeof fetchUser>;
    // FetchUserResult = ?
    • A.{ id: string; name: string }
    • B.string
    • C.Promise<{ id: string; name: string }>
    • D.(id: string) => Promise<{ id: string; name: string }>
    Show answer

    Answer: C. Promise<{ id: string; name: string }>

    ReturnType<T> extracts the return type of a function type — for async functions, that's the full Promise<...> type: To get the unwrapped type, use Awaited:

    From the quiz Utility Types

  4. 14.What is the difference between instance and static members?

    javascript
    class Counter {
      static count: number = 0;
      id: number;
    
      constructor() {
        Counter.count++;
        this.id = Counter.count;
      }
    
      static reset() { Counter.count = 0; }
    }
    • A.static count belongs to each instance; id is shared across all instances
    • B.Counter.count and new Counter().count access the same memory
    • C.static members can only be numbers
    • D.static count belongs to the class itself (shared across all instances); id belongs to each instance
    Show answer

    Answer: D. static count belongs to the class itself (shared across all instances); id belongs to each instance

    Static members live on the class constructor itself, not on individual instances:

    From the quiz Inheritance & Polymorphism

  5. 15.How does the in operator help TypeScript narrow types?

    javascript
    type Cat = { meow: () => void };
    type Dog = { bark: () => void };
    
    function makeSound(animal: Cat | Dog) {
      if ('meow' in animal) {
        animal.meow(); // ?
      }
    }
    • A.in checks if the property exists at runtime but TypeScript still sees Cat | Dog
    • B.TypeScript narrows animal to Cat inside the if block because only Cat has meow
    • C.in only works with classes, not type aliases
    • D.TypeScript narrows animal to never inside the if
    Show answer

    Answer: B. TypeScript narrows animal to Cat inside the if block because only Cat has meow

    The in operator narrows to the union members that include the checked property: This is the idiomatic way to narrow discriminated object unions where the discriminant is a property name.

    From the quiz Mapped & Conditional Types

  6. 16.What does Partial<User> produce?

    javascript
    interface User {
      name: string;
      email: string;
      age: number;
    }
    
    function updateUser(id: string, patch: Partial<User>): void { /* ... */ }
    • A.A type where all properties are required (same as User)
    • B.A type containing only the first property of User
    • C.A type where all properties of User become optional
    • D.A type where all properties become null
    Show answer

    Answer: C. A type where all properties of User become optional

    Partial<T> is a built-in TypeScript utility type that makes all properties of T optional: This is extremely useful for PATCH-style update functions.

    From the quiz TypeScript Intermediate

  7. 17.What is the resolved type here?

    javascript
    async function fetchData(): Promise<{ users: { id: string; name: string }[] }> {
      return { users: [] };
    }
    
    type ResponseData = Awaited<ReturnType<typeof fetchData>>;
    type UserList = ResponseData['users'];
    type User = UserList[number];
    • A.User = string
    • B.User = { users: { id: string; name: string }[] }
    • C.User = { id: string; name: string }
    • D.User = unknown
    Show answer

    Answer: C. User = { id: string; name: string }

    Step by step: 1. ReturnType<typeof fetchData> = Promise<{ users: { id: string; name: string }[] }> 2. Awaited<...> = { users: { id: string; name: string }[] } 3. ResponseData['users'] = { id: string; name: string }[] 4. UserList[number] = { id: string; name: string } — accessing array element type

    From the quiz Template Literals & Inference

  8. 18.What does skipLibCheck: true do?

    javascript
    { "compilerOptions": { "skipLibCheck": true } }
    • A.Skips type-checking of all .ts files in your project
    • B.Skips importing external libraries
    • C.Skips type-checking of declaration files (.d.ts) — including those in node_modules
    • D.Disables strict mode for third-party code
    Show answer

    Answer: C. Skips type-checking of declaration files (.d.ts) — including those in node_modules

    skipLibCheck: true skips type-checking of ALL .d.ts files:

    From the quiz Decorators & Project Setup

  9. 19.What does Parameters extract?

    javascript
    function createUser(name: string, age: number, role: 'admin' | 'user'): void { /* ... */ }
    
    type CreateArgs = Parameters<typeof createUser>;
    • A.[string, number, 'admin' | 'user'] — a tuple of parameter types
    • B.string | number | 'admin' | 'user' — a union of parameter types
    • C.{ name: string; age: number; role: 'admin' | 'user' } — an object
    • D.void
    Show answer

    Answer: A. [string, number, 'admin' | 'user'] — a tuple of parameter types

    Parameters<T> extracts the parameter types as a tuple:

    From the quiz Utility Types

  10. 20.What does super do in a subclass constructor?

    javascript
    class Animal {
      constructor(public name: string) {}
      speak() { return `${this.name} makes a sound.`; }
    }
    
    class Dog extends Animal {
      constructor(name: string, public breed: string) {
        super(name); // ?
      }
    }
    • A.super(name) calls Animal.speak() method
    • B.super is only valid in method overrides, not constructors
    • C.super(name) calls the parent class constructor — required before using this in a subclass constructor
    • D.super(name) copies all parent properties to the child
    Show answer

    Answer: C. super(name) calls the parent class constructor — required before using this in a subclass constructor

    In a derived class constructor, super(...) must be called before any use of this. It invokes the parent class constructor:

    From the quiz Inheritance & Polymorphism

Senior level TypeScript questions

  1. 21.What type is produced?

    javascript
    type JSONValue =
      | string
      | number
      | boolean
      | null
      | JSONValue[]
      | { [key: string]: JSONValue };
    
    type IsJSON<T> = T extends JSONValue ? true : false;
    
    type A = IsJSON<string>;
    type B = IsJSON<{ x: number; y: number }>;
    type C = IsJSON<Date>;
    type D = IsJSON<undefined>;
    • A.A = true, B = true, C = true, D = true
    • B.A = true, B = true, C = false, D = false
    • C.A = true, B = false, C = false, D = false
    • D.A = true, B = true, C = false, D = true
    Show answer

    Answer: B. A = true, B = true, C = false, D = false

    JSONValue includes string, numbers, booleans, null, arrays, and plain objects:

    From the quiz Conditional Types & Infer

  2. 22.What does this declaration file accomplish?

    javascript
    // src/global.d.ts
    declare module '*.svg' {
      const content: string;
      export default content;
    }
    
    declare module '*.md' {
      const content: string;
      export default content;
    }
    • A.Creates runtime handlers for .svg and .md imports
    • B.These declarations are redundant — TypeScript handles all file types natively
    • C.Converts SVG files to strings automatically during compilation
    • D.Tells TypeScript the type of these file imports — prevents "cannot find module" errors when importing non-JS files
    Show answer

    Answer: D. Tells TypeScript the type of these file imports — prevents "cannot find module" errors when importing non-JS files

    TypeScript only understands JavaScript/TypeScript modules natively. For other file types: The actual transformation is done by the bundler (Vite, webpack) — the ambient module declaration just tells TypeScript the types.

    From the quiz Compiler API & References

  3. 23.What is the return type of compose?

    javascript
    function compose<A, B, C>(
      f: (b: B) => C,
      g: (a: A) => B
    ): (a: A) => C {
      return (a: A) => f(g(a));
    }
    
    const addOne = (n: number): number => n + 1;
    const toString = (n: number): string => String(n);
    
    const addOneThenString = compose(toString, addOne);
    const result = addOneThenString(5); // ?
    • A."5" — only the second function applies
    • B.6 — typed as number
    • C."6" — 5 + 1 = 6, then String(6) = "6"; typed as string
    • D.Compile error — compose doesn't infer types
    Show answer

    Answer: C. "6" — 5 + 1 = 6, then String(6) = "6"; typed as string

    TypeScript infers the type parameters:
    • g = addOne: (number) => number → A = number, B = number
    • f = toString: (number) => string → B = number, C = string
    • compose(toString, addOne) → (number) => string

    From the quiz Advanced Generics

  4. 24.What does a method decorator receive?

    javascript
    function Log(target: any, key: string, descriptor: PropertyDescriptor) {
      const original = descriptor.value;
      descriptor.value = function(...args: any[]) {
        console.log(`Calling ${key} with`, args);
        return original.apply(this, args);
      };
      return descriptor;
    }
    
    class Service {
      @Log
      process(data: string): string { return data.toUpperCase(); }
    }
    • A.target = the instance, key = the method name, descriptor = the method function
    • B.target = the class prototype (for instance methods), key = the method name, descriptor = the property descriptor (wrapping the function)
    • C.target = the class constructor, key = the class name, descriptor = all methods
    • D.Method decorators only receive target — the other parameters are optional
    Show answer

    Answer: B. target = the class prototype (for instance methods), key = the method name, descriptor = the property descriptor (wrapping the function)

    Method decorator parameters:
    • target — the prototype of the class (for instance methods) or the constructor (for static methods)
    • key — the name of the decorated method
    • descriptor — the PropertyDescriptor containing .value (the function), .writable, .enumerable

    From the quiz Advanced OOP Patterns

  5. 25.What is the difference between Extract and Exclude?

    javascript
    type A = Extract<string | number | boolean, string | number>;
    type B = Exclude<string | number | boolean, string | number>;
    • A.A = string | number, B = boolean
    • B.A = boolean, B = string | number
    • C.Both are string | number | boolean
    • D.A = never, B = boolean
    Show answer

    Answer: A. A = string | number, B = boolean

    • Extract<T, U> keeps only the members of T that are assignable to U
    • Exclude<T, U> removes the members of T that are assignable to U

    From the quiz Advanced Type Engineering

  6. 26.What is the correct way to handle each shape's area calculation using a discriminated union?

    javascript
    type Shape =
      | { kind: "circle"; radius: number }
      | { kind: "square"; side: number }
      | { kind: "rectangle"; width: number; height: number };
    • A.Use shape.kind with switch or if to narrow the union to a specific member
    • B.Use typeof shape to narrow between shapes
    • C.Use instanceof to narrow between shapes
    • D.Cast shape as any and access properties freely
    Show answer

    Answer: A. Use shape.kind with switch or if to narrow the union to a specific member

    A discriminated union has a common literal property (the discriminant) — here kind. TypeScript narrows the type when you check that property: TypeScript provides exhaustiveness checking: if you miss a case, the function may not return in all branches, which TypeScript can catch.

    From the quiz TypeScript Advanced

  7. 27.What does this complex mapped type produce?

    javascript
    type Serialize<T> = {
      [K in keyof T]: T[K] extends Date
        ? string
        : T[K] extends (infer U)[]
        ? Serialize<U>[]
        : T[K] extends object
        ? Serialize<T[K]>
        : T[K];
    };
    
    interface Data {
      name: string;
      createdAt: Date;
      tags: string[];
      address: { city: string; updatedAt: Date };
    }
    
    type SerializedData = Serialize<Data>;
    • A.string
    • B.{ name: string; createdAt: Date; tags: string[]; address: { city: string; updatedAt: Date } }
    • C.{ name: string; createdAt: string; tags: string[]; address: { city: string; updatedAt: string } }
    • D.Data unchanged
    Show answer

    Answer: C. { name: string; createdAt: string; tags: string[]; address: { city: string; updatedAt: string } }

    Serialize<T> recursively transforms Date → string:

    From the quiz Conditional Types & Infer

  8. 28.When should you use triple-slash references?

    javascript
    /// <reference types="node" />
    /// <reference path="../global.d.ts" />
    /// <reference lib="dom" />
    
    // Top of a .ts file
    • A.Triple-slash directives are legacy — prefer import type for code; they're still useful for global .d.ts files and forcing type inclusion
    • B.Triple-slash directives are the modern way to import types in TypeScript
    • C.They only work in .d.ts files, not regular .ts files
    • D./// <reference types="node" /> replaces @types/node in package.json
    Show answer

    Answer: A. Triple-slash directives are legacy — prefer import type for code; they're still useful for global .d.ts files and forcing type inclusion

    Triple-slash directives are compiler directives (not imports):

    From the quiz Compiler API & References

  9. 29.What does Awaited<T> unwrap?

    javascript
    type T1 = Awaited<Promise<string>>;
    type T2 = Awaited<Promise<Promise<number>>>;
    type T3 = Awaited<string>;
    • A.T1 = string, T2 = Promise<number>, T3 = string
    • B.T1 = string, T2 = number, T3 = never
    • C.T1 = Promise<string>, T2 = Promise<Promise<number>>, T3 = string
    • D.T1 = string, T2 = number, T3 = string
    Show answer

    Answer: D. T1 = string, T2 = number, T3 = string

    Awaited<T> recursively unwraps Promise types: This replaces older patterns like ReturnType<typeof fn> for async functions where you'd need Awaited<ReturnType<...>>.

    From the quiz Advanced Generics

  10. 30.What is the difference between #field and private field?

    javascript
    class A {
      private tsPrivate = 1;
      #jsPrivate = 2;
    }
    
    const a = new A();
    (a as any).tsPrivate; // ?
    (a as any).jsPrivate; // ?
    • A.Both are inaccessible — they compile to the same JavaScript
    • B.tsPrivate is accessible via as any at runtime (TypeScript-only check); #jsPrivate is truly inaccessible at runtime (JavaScript native enforcement)
    • C.#jsPrivate is only accessible from subclasses
    • D.private fields can be accessed via reflection; # fields cannot be reflected on
    Show answer

    Answer: B. tsPrivate is accessible via as any at runtime (TypeScript-only check); #jsPrivate is truly inaccessible at runtime (JavaScript native enforcement)

    TypeScript private is compile-time only — it compiles to a regular JavaScript property, accessible at runtime: JavaScript #privateField is runtime-enforced — it's a WeakMap-based private field in JavaScript itself: Even with reflection or Object.keys(), # fields are hidden.

    From the quiz Advanced OOP Patterns

Practise 650+ more TypeScript questions

Timed quizzes with instant feedback, the questions you miss coming back until they stick, coding challenges and AI mock interviews — free to start.