cswork / libraryOpen practice workspace

Articles

TypeScript Interview Questions for Senior Frontend Engineers: Types, Generics, and Runtime Gaps

Practice senior TypeScript interview questions on types, generics, narrowing, React, runtime validation, TSConfig, and the production gaps interviewers test.

Most candidates can define a union or explain a generic. A senior TypeScript interview usually begins where that syntax lesson ends: What happens when the compiler is satisfied but the browser receives the wrong data?

This guide covers the TypeScript questions that reveal production judgment, not just vocabulary. You will practice type relationships, generics, narrowing, React and DOM boundaries, compiler settings, and the runtime gaps that strong frontend engineers make explicit.

Answer before reading a solution. A senior signal is not knowing more syntax; it is choosing a type design that makes the system easier to change safely.

Quick Answer: What Do Senior TypeScript Interviews Test?

Expect fewer definitions and more questions combining TypeScript with APIs, UI state, React components, and failure handling. Interviewers want types that communicate invariants without hiding JavaScript's runtime behavior.

AreaTypical promptSenior signal
Type modelingRepresent loading, success, and error statesImpossible states cannot compile
GenericsDesign a reusable table or selector APIPreserves useful relationships without type gymnastics
Runtime safetyTrust data from an API, storage, or message eventValidates at the boundary before narrowing
React and DOMType events, refs, children, and component variantsUses inference and models the actual public contract
ToolingChoose strictness flags for a large codebaseExplains migration cost and the bugs each flag exposes

Core Type-System Questions

1. What TypeScript information exists at runtime?

Strong answer: most TypeScript types are erased during compilation. Interfaces, type aliases, generic parameters, and assertions do not validate or transform a runtime value. The emitted JavaScript follows JavaScript semantics.

That is why payload as User cannot make an API response a valid user. Runtime checks must come from JavaScript control flow, a validation function, or a schema library. Mention exceptions carefully: features such as enums can emit JavaScript, but that does not turn the general type system into runtime validation.

2. How do any, unknown, and never differ?

any disables checking and lets unsafety spread through later expressions. unknown accepts any value but forces you to narrow it before use, which makes it the safer type for untrusted boundaries. never represents a value that should be impossible and is useful for exhaustive checks.

A contained any may be pragmatic during migration, but it should not silently enter a shared component or API contract.

3. When would you choose an interface over a type alias?

Both can describe object shapes and often work interchangeably. Interfaces support declaration merging and provide a natural extension model. Type aliases can express unions, tuples, primitives, mapped types, and conditional types.

Use interfaces when intentional augmentation matters and type aliases when composition goes beyond an object contract. Consistency matters more than a universal rule.

4. How do discriminated unions improve UI state?

They encode each valid state as a separate object with a literal discriminant. A loading state cannot accidentally contain stale success data, and a success branch can access data without optional-property assertions. A never check makes newly added states fail compilation until every consumer handles them.

type RequestState<T> =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: T }
  | { status: "error"; message: string };

function assertNever(value: never): never {
  throw new Error(`Unhandled state: ${String(value)}`);
}

Generics and Type Relationships

5. What problem should a generic solve?

A useful generic preserves a relationship between inputs and outputs. It is not merely a placeholder that makes a function look reusable. In this example, the key must belong to the object and the return type changes with that key:

function getProperty<T, K extends keyof T>(
  object: T,
  key: K
): T[K] {
  return object[key];
}

Compare that with returning unknown or any, which loses the relationship. Also watch for a generic parameter that appears only once; a concrete type or union may communicate the contract better.

6. How do constraints and inference affect a component API?

Imagine a reusable table. A strong design might infer the row type from rows, then constrain each column key to keyof Row. The caller should not have to repeat a type argument that TypeScript can infer.

A perfectly inferred API can become unreadable when it depends on several conditional types. Protect the relationship callers need and keep the signature understandable.

7. When are mapped and conditional types useful?

Mapped types transform properties across an existing shape; conditional types describe a relationship that selects a type based on another type. They are valuable for library surfaces, form models, event maps, and generated client types.

They become a warning sign when every prop needs an IDE tooltip. Consider error readability and maintenance cost, not only what the type system can express.

8. What is the difference between an annotation, satisfies, and an assertion?

An annotation checks a value against a declared type and may widen what consumers see. satisfies checks compatibility while preserving the expression's more specific inferred type. An as assertion tells the compiler to trust the developer and adds no runtime check.

Use satisfies for configuration maps needing validation and precise inference. Treat assertions as localized evidence, not a routine error silencer.

Runtime-Gap Questions

9. Why is asserting an API response unsafe?

The network is outside the compiler's trust boundary. A backend can deploy independently, a field can be absent, a proxy can return an error document, or cached data can use an older shape. Start with unknown, validate once, then pass a trusted domain type inward.

type User = { id: string; name: string };

function isUser(value: unknown): value is User {
  if (typeof value !== "object" || value === null) return false;
  const record = value as Record<string, unknown>;
  return typeof record.id === "string"
    && typeof record.name === "string";
}

const raw: unknown = await response.json();
if (!isUser(raw)) throw new Error("Invalid user response");
const user = raw;

For complex payloads, use a tested runtime schema rather than hand-writing a forest of predicates. A type predicate is only as truthful as its implementation.

10. Which other frontend values are untrusted?

Other untrusted values include localStorage, URL parameters, postMessage events, feature flags, third-party SDKs, and server-rendered JSON. Generated API types still do not prove what arrived.

11. What can go wrong with DOM assertions and non-null assertions?

document.getElementById may return null, and the element may not be the subtype you expect. Writing as HTMLInputElement or adding ! suppresses the compiler without changing the DOM.

Check presence and, when needed, instanceof HTMLInputElement. In React, type public contracts while letting hook and callback inference handle local details.

12. Can TypeScript guarantee a React component receives specific JSX children?

Not reliably at runtime, and React's own TypeScript guide notes limits on describing only a particular JSX child type. If composition rules are essential, design a clearer API, such as passing data or render functions, and add development-time or runtime checks where appropriate.

Know where static types stop, then choose an API that needs fewer fragile assumptions.

TSConfig Questions Senior Candidates Should Expect

Saying "turn on strict mode" is a start. A stronger answer connects configuration to concrete bugs and explains how to introduce stricter checks without freezing product delivery.

SettingWhat it exposesSenior discussion
strictA family of stronger type checksEnable for new code; stage legacy migration with ownership and metrics
strictNullChecksMissing null and undefined handlingDesign states and API contracts instead of spreading non-null assertions
noUncheckedIndexedAccessMissing array or dictionary entriesAdds undefined where an indexed lookup may miss
exactOptionalPropertyTypesDifference between absent and present-as-undefinedUseful for patches, object spread, and serialization semantics

For a large migration, discuss package boundaries, CI checks, an error baseline, and preventing new unsafe escape hatches. That shows organizational judgment as well as language knowledge.

A Senior Frontend Coding Scenario

An interviewer may ask you to build a typed autocomplete component backed by an API. Clarify the item shape, label and identity functions, controlled versus uncontrolled state, keyboard accessibility, loading and error states, request cancellation, stale-response races, and how results are validated.

A strong solution remains reusable without erasing useful types, validates network data, models async states explicitly, and tests behavior.

Once a company is scheduled, use company-specific interview prep so a TypeScript study plan does not crowd out component coding, JavaScript, accessibility, or architecture.

How Interviewers Score the Answer

Syntax is the floor. Interviewers care whether the contract and reasoning survive changing requirements.

Weak signalStrong senior signal
Adds as until errors disappearExplains the missing evidence and validates the boundary
Builds a highly clever genericOptimizes for caller ergonomics and readable failures
Makes every field optionalUses unions to model valid states and invariants
Treats generated types as validationSeparates compile-time contracts from runtime trust
Answers only the TypeScript layerConnects types to UX, tests, rollout, and team maintenance

A 7-Day TypeScript Interview Practice Plan

Days 1-2: explain the core type system aloud: structural typing, unions, narrowing, unknown, never, assertions, and strict null handling. Use small examples and state what exists at runtime.

Days 3-4: design two generic APIs: a table and a form-field adapter. Remove unnecessary type parameters, inspect error messages, and test whether inference works for callers.

Days 5-6: build one component that consumes untrusted JSON. Add runtime validation, explicit async states, stale-request protection, accessibility, and behavioral tests. Then review frontend system design preparation for the architecture layer.

Day 7: run a 45-minute mock using an unseen frontend prompt. Spend the last ten minutes explaining trade-offs and testing failure cases. Add behavioral and leadership practice if the loop is senior-level.

Frequently Asked Questions

What TypeScript questions are asked in senior frontend interviews?

Expect type modeling, generics, narrowing, React and DOM contracts, strict settings, and runtime validation inside coding or design scenarios.

How deep should I study TypeScript generics?

Preserve input-output relationships, use keyof and indexed access, add useful constraints, and read common mapped or conditional types. Avoid unnecessary type-level puzzles.

Does TypeScript prevent runtime errors?

It prevents many statically provable mistakes, but types are generally erased. External data, assertions, DOM state, and incorrect validators can still fail at runtime.

Should senior frontend engineers avoid any completely?

Avoid letting it leak into shared contracts. A small, documented escape hatch can be reasonable during migration or around a broken third-party type, but isolate it, validate assumptions, and create a path to remove it.

Final Takeaway

The senior TypeScript skill is boundary judgment. Use the type system to preserve relationships and eliminate impossible UI states, but never confuse a compiler promise with runtime evidence.

Official Sources

Language behavior and examples were checked against the official TypeScript documentation for erased types and runtime behavior, generics, narrowing and exhaustiveness, conditional types, strict mode, unchecked indexed access, and exact optional properties. React-specific limitations were checked against the official React TypeScript guide on August 13, 2026.