AI Interview

Menu
Frontend DevelopmentTypeScriptJavaScriptFrontend

TypeScript Interview Questions & Answers (2026)

A practical, technically accurate guide to the TypeScript interview questions you will actually be asked in 2026, covering types vs interfaces, generics, utility types, unknown vs any, narrowing, discriminated unions, and decorators with real examples.

AI Mock Interview TeamSeptember 30, 202615 min read

TypeScript has become the default language for serious frontend and Node.js work, so interviewers now expect fluency in its type system, not just JavaScript. This guide covers the TypeScript questions most commonly asked in 2026, grouped by topic, with accurate answers and real code you can study and adapt. Focus on understanding the why behind each feature, because interviewers value engineers who use the type system to prevent bugs rather than fight it.

Types, Interfaces, and the Basics

What is the difference between a type alias and an interface?

Both describe the shape of an object, and for most cases they are interchangeable. Interfaces support declaration merging, meaning two interfaces with the same name are combined, which is useful for augmenting third-party types. Interfaces are also limited to describing object and function shapes and extend other interfaces with the extends keyword. Type aliases are more flexible: they can represent unions, intersections, tuples, primitives, and mapped or conditional types, which interfaces cannot. A common convention is to use interfaces for public object contracts and type aliases for unions and more complex type expressions.

typescript
// Interface: object contract, supports extends and declaration merging
interface User {
  id: string;
  name: string;
}

interface User {
  // Merged into the same User interface
  email: string;
}

// Type alias: unions, intersections, and primitives
type Status = 'active' | 'suspended' | 'deleted';
type Admin = User & { role: 'admin' };
type Id = string | number;

What is the difference between unknown, any, and never?

any disables type checking entirely; a value typed as any can be assigned to and from anything, which defeats the purpose of TypeScript and should be avoided. unknown is the type-safe counterpart: you can assign anything to an unknown, but you cannot use it until you narrow it with a type guard, so it forces you to check before acting. never represents a value that can never occur, such as the return type of a function that always throws or the type in an exhaustiveness check after all union members are handled. Prefer unknown over any at boundaries like JSON parsing and use never to enforce exhaustive handling.

typescript
// unknown forces a check before use
function parse(input: unknown): string {
  if (typeof input === 'string') {
    return input.toUpperCase(); // safe: narrowed to string
  }
  throw new Error('Expected a string');
}

// never for exhaustiveness checking
type Shape = { kind: 'circle' } | { kind: 'square' };

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return 1;
    case 'square':
      return 2;
    default: {
      const _exhaustive: never = shape; // errors if a case is missed
      return _exhaustive;
    }
  }
}

Generics

What are generics and why are they useful?

Generics let you write reusable code that works over a variety of types while preserving type information, instead of falling back to any. A generic function or type takes one or more type parameters that the caller or the compiler fills in. This means a function like identity can return exactly the type it received, and a container like Array can be typed for its element type. Generics are the foundation of type-safe utility functions, collections, and API clients.

What are generic constraints?

A generic constraint uses the extends keyword to restrict what types a type parameter can accept, so you can safely rely on certain properties. For example, a function that reads a property by key can constrain the key to keyof the object type, guaranteeing the key exists and letting TypeScript infer the exact return type. Constraints turn generics from unbounded placeholders into safe, expressive tools.

typescript
// Constrained generic: K must be a key of T
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { id: '1', name: 'Ada', age: 30 };
const name = getProp(user, 'name'); // inferred as string
const age = getProp(user, 'age');   // inferred as number
// getProp(user, 'email'); // compile error: 'email' is not a key

Generics and utility types are much easier to explain when you have said the words out loud a few times. Rehearse walking through a generic function's inference step by step using the free AI Mock Interview question generator at /tools/question-generator, which gives instant feedback on both correctness and clarity.

Utility Types

What are the most common built-in utility types?

TypeScript ships mapped utility types that transform existing types. Partial<T> makes all properties optional; Required<T> makes them all required. Readonly<T> makes properties immutable. Pick<T, K> selects a subset of keys, while Omit<T, K> removes keys. Record<K, V> builds an object type with keys K and values V. Others include Exclude, Extract, NonNullable, and ReturnType. Knowing these lets you derive new types from existing ones instead of duplicating definitions, which keeps types in sync as the code evolves.

typescript
interface Product {
  id: string;
  name: string;
  price: number;
  description: string;
}

// All optional, e.g. for a PATCH update payload
type ProductUpdate = Partial<Product>;

// Only the fields a list view needs
type ProductSummary = Pick<Product, 'id' | 'name' | 'price'>;

// Everything except the internal id
type ProductInput = Omit<Product, 'id'>;

// A lookup keyed by product id
type ProductMap = Record<string, Product>;

Can you implement a simplified version of Partial or Pick yourself?

Yes, and interviewers often ask this to test your grasp of mapped types. Partial iterates over the keys of T with a mapped type and adds the optional modifier. Pick iterates over a union of specified keys and copies each property type. Being able to write these from scratch shows you understand keyof, indexed access types, and mapped type syntax rather than just memorizing names.

typescript
// Reimplementing built-in utility types with mapped types
type MyPartial<T> = {
  [P in keyof T]?: T[P];
};

type MyPick<T, K extends keyof T> = {
  [P in K]: T[P];
};

type MyReadonly<T> = {
  readonly [P in keyof T]: T[P];
};

Narrowing and Type Guards

What is type narrowing and how does control-flow analysis help?

Narrowing is how TypeScript refines a broad type to a more specific one within a code branch based on runtime checks. Using typeof, instanceof, the in operator, equality checks, or truthiness, the compiler tracks which type is possible at each point through control-flow analysis. For instance, inside an if (typeof x === 'string') block, x is treated as a string. This lets you handle union types safely without casts and is central to writing correct TypeScript.

What is a user-defined type guard?

A user-defined type guard is a function whose return type is a type predicate of the form arg is SomeType. When the function returns true, TypeScript narrows the argument to SomeType in the calling code. These are useful when a simple typeof or instanceof check is not enough, for example validating that an unknown value matches an interface shape. They encapsulate validation logic while giving the compiler the narrowing information it needs.

typescript
interface Cat {
  meow: () => void;
}
interface Dog {
  bark: () => void;
}

// User-defined type guard using a type predicate
function isCat(animal: Cat | Dog): animal is Cat {
  return 'meow' in animal;
}

function speak(animal: Cat | Dog): void {
  if (isCat(animal)) {
    animal.meow(); // narrowed to Cat
  } else {
    animal.bark(); // narrowed to Dog
  }
}

Discriminated Unions and Decorators

What is a discriminated union and why is it powerful?

A discriminated union (also called a tagged union) is a union of object types that share a common literal property, the discriminant, such as a kind or type field. TypeScript uses that shared literal to narrow the union in a switch or if statement, so each branch knows the exact member type and its specific properties. Combined with a never check in the default case, discriminated unions give you exhaustive, compiler-verified handling of every variant, which is ideal for modeling state, actions, and API responses.

typescript
// Discriminated union for an async request state
type RequestState =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: string[] }
  | { status: 'error'; message: string };

function render(state: RequestState): string {
  switch (state.status) {
    case 'idle':
      return 'Idle';
    case 'loading':
      return 'Loading...';
    case 'success':
      return state.data.join(', '); // data is available here
    case 'error':
      return state.message;         // message is available here
  }
}

What are decorators and where are they used?

Decorators are special functions prefixed with @ that attach metadata or modify classes, methods, accessors, properties, or parameters. They were standardized in the ECMAScript decorators proposal and are supported by modern TypeScript, though older code may rely on the experimentalDecorators flag for the legacy design. Frameworks such as Angular and NestJS use decorators heavily for dependency injection, routing, and validation, for example @Injectable, @Controller, or @Component. In an interview, explain that decorators are a metaprogramming tool and note whether you mean the standardized or legacy form.

There are two decorator systems in the TypeScript world: the legacy experimentalDecorators implementation (used by Angular and NestJS) and the newer standardized ECMAScript decorators. Their signatures differ, so be clear about which one you are describing and never assume metadata reflection is available without reflect-metadata.

Frequently Asked Questions

Do I need to memorize every utility type for an interview?

No. Interviewers care that you know the workhorses (Partial, Pick, Omit, Record, Readonly, ReturnType) and can reason about how they work rather than reciting all of them. If you understand keyof, mapped types, and conditional types, you can derive or reimplement any utility type on the spot, which is far more impressive than memorization. Focus your prep on the mechanics behind the types.

How is a TypeScript interview different from a JavaScript one?

A JavaScript interview centers on language mechanics like closures, the event loop, prototypes, and asynchronous code. A TypeScript interview assumes that foundation and adds the type system: generics, narrowing, utility types, discriminated unions, and how types prevent runtime errors. You will often be asked to type an existing JavaScript function, so be ready to talk about both runtime behavior and compile-time typing together.

What is the best way to practice TypeScript interview questions out loud?

Because TypeScript interviews mix live coding with conceptual discussion, practice both writing typed code and explaining your reasoning aloud. Rehearse narrating how the compiler infers a generic, why unknown is safer than any, or how a discriminated union enables exhaustiveness. AI Mock Interview provides a free voice-based TypeScript track and a question generator at /tools/question-generator that gives instant feedback on your technical accuracy and communication clarity.

Practice with AI Mock Interviews

Put your knowledge to the test with our AI interviewer.