Skip to content

Boarding pass · TypeScript Intermediate

TypeScript · Intermediate interview

An AI mock interview for developers comfortable with TypeScript basics. Go deeper into generics with constraints, the utility and mapped types, discriminated unions and type guards, and structural typing.

20–30 minEstimated6 questionsTailored live12 model answersTo study
  • Voice interview
  • Live feedback
  • Browser-only
  • No installation required

Your report · sample

AI Readiness Score

/100
Content score English score

Finish the mock and get this report — scored on content and English, with concrete tips and a model answer for every question, plus a study plan.

Your flight path

Five steps to interview-ready.

From a quick warm-up to a personalised study plan — here's the whole loop, and what you get at each gate.

  1. Step 01

    Preparation

    Skim the topics and warm up — you're briefed before takeoff.

  2. Step 02

    AI Interview

    A realistic AI interviewer asks tailored questions — answer by voice or text.

  3. Step 03

    Instant Score

    Finish and get a 0–100 readiness score across content and English.

  4. Step 04

    AI Feedback

    Concrete tips and a rewritten model answer for every response.

  5. Step 05

    Study Plan

    A personalised plan targets your weakest areas — so the next run scores higher.

Preview the AI demo

See one answer scored, end to end.

The whole loop on sample data — question, your answer, instant feedback and a study plan. Hover to pause.

aevrofy.com/session · live demoPlaying

Interviewer · Question 1

“Tell me about yourself.”

Who it's for

  • Developers using TypeScript daily
  • Engineers who want to type tricky code well
  • Anyone targeting mid-level TS-heavy roles
  • Devs sharpening before interviews

What you'll practice

  • Generic constraints and keyof/indexed access
  • Utility types and writing mapped types
  • Discriminated unions and type guards
  • Structural typing and its gotchas

Topics covered

What this level expects.

Generics

  • Constraints (extends)
  • keyof & indexed access
  • Default params

Utility & mapped

  • Partial/Pick/Omit/Record
  • Mapped types
  • as const

Narrowing

  • Discriminated unions
  • Type predicates (is)
  • Exhaustiveness

Structural typing

  • Duck typing
  • Excess property checks
  • Assertions vs narrowing

Practice questions

12 questions, with model answers.

Read them, then run the live mock to answer out loud and get scored. Tap any question to reveal a model answer.

01How do generic constraints with extends work?

A constraint restricts what a type parameter can be, so you can rely on certain properties inside the generic. <T extends { id: string }> means T can be any type that has an id string, letting you access x.id safely. Without the constraint the parameter is effectively unknown and you can't touch its members.

function byId<T extends { id: string }>(items: T[], id: string) {
  return items.find(i => i.id === id);
}
02What do keyof and indexed access types do?

keyof T produces a union of T's property names, so keyof { a: 1; b: 2 } is 'a' | 'b'. An indexed access type T[K] gives the type of a property by key. Together they let you write functions that are type-safe over keys — like a getter that only accepts real keys and returns the matching value type.

function get<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
03What are default and inferred type parameters?

A generic can have a default (<T = string>) used when the caller doesn't supply or the compiler can't infer one. Usually you let TypeScript infer type arguments from the values you pass, only specifying them explicitly when inference is impossible or you want to widen/narrow deliberately. Defaults are handy for flexible APIs where most callers want a common type.

04How do Partial, Pick, Omit, and Record work?

They're built-in mapped types. Partial<T> makes all properties optional; Pick<T, K> keeps only the listed keys; Omit<T, K> removes the listed keys; Record<K, V> builds an object type with keys K and values V. They let you derive new types from existing ones instead of duplicating shapes — for example, an update DTO as Partial<User>.

05How would you write a mapped type yourself?

A mapped type iterates over keys with [K in keyof T] and transforms each property's type. For example, a Readonly-like type adds the readonly modifier, and you can make properties optional or change their value type. This is the mechanism the built-in utilities are built on.

type Nullable<T> = { [K in keyof T]: T[K] | null };
06What does 'as const' do?

as const makes a literal deeply readonly and narrows it to its most specific literal types instead of widening — so { role: 'admin' } as const has role of type 'admin', not string, and arrays become readonly tuples. It's useful for config objects, action-type constants, and deriving union types from values with typeof.

const ROLES = ["admin", "user"] as const;
type Role = typeof ROLES[number]; // "admin" | "user"
07What is a discriminated union and why is it useful?

It's a union of object types that share a common literal 'tag' property (the discriminant). Switching on that tag lets TypeScript narrow to the exact member in each branch, so you get type-safe access to the fields specific to that case. It's the idiomatic way to model states, events, or results.

type Result = { ok: true; data: string } | { ok: false; error: string };
if (r.ok) r.data; else r.error;
08What is a user-defined type guard?

It's a function whose return type is a type predicate (arg is Type). When it returns true, TypeScript narrows the argument to that type in the calling branch. You use it to encapsulate a runtime check — like validating a shape — and teach the compiler about the result.

function isUser(x: unknown): x is User {
  return !!x && typeof (x as User).id === "string";
}
09How do you make a switch over a union exhaustive?

Add a default branch that assigns the value to a never typed variable. If you later add a new union member and forget to handle it, the value won't be never and the compiler errors, forcing you to update the switch. It turns 'I forgot a case' into a compile-time failure.

default: { const _exhaustive: never = value; throw new Error(_exhaustive); }
10What is structural typing and how does it differ from nominal typing?

TypeScript types are compatible based on their shape, not their declared name — if an object has the required members, it's assignable, even if it was never declared as that type. Languages like Java are nominal: compatibility requires the explicit type/inheritance. Structural typing is flexible and matches how JavaScript works, but it means two unrelated types with the same shape are interchangeable.

11What are excess property checks?

When you assign an object literal directly to a typed target, TypeScript flags properties that aren't in the type, even though structural typing would otherwise allow extra properties. This catches typos like spelling a key wrong in a config. The check only applies to fresh object literals — assign through a variable and it relaxes, which is a common surprise.

12What's the difference between a type assertion and narrowing, and why are assertions risky?

Narrowing proves a type to the compiler through a runtime check, so it's safe. An assertion (x as Foo) just tells the compiler to trust you without any check — if you're wrong, you get a runtime error the type system can't catch. Use assertions sparingly, for cases the compiler genuinely can't follow, and prefer guards/validation that actually verify the value.

Preparation tips

Walk in ready.

  • Practise writing a mapped type from scratch
  • Model a state machine with a discriminated union
  • Know when an assertion is lying to the compiler
  • Use keyof to keep object access type-safe

Ready for the real thing?

Run a 6-question TypeScript mock interview, answer out loud, and get a readiness score with tips and model answers.

More intermediate interviews

Aevrofy · TypeScript intermediate interview prep