Senior TypeScript Questions
TL;DR
Senior interviews focus less on syntax (how to write an interface) and more on architecture, build systems, performance, and the underlying philosophy of the language.
1. What is the difference between Nominal and Structural Typing?
TypeScript uses Structural Typing (Duck Typing). It determines type compatibility based on the shape of the data (does it have the required properties?), not the explicit declaration. Languages like Java use Nominal Typing, where a class is only compatible if it explicitly implements the exact named interface.
2. Why does typeof null return "object" in JavaScript, and how does TypeScript handle this?
This is a famous legacy bug in JavaScript dating back to 1995. Because TS is a superset of JS, typeof null === "object" remains true. To protect against this, TS uses the strictNullChecks compiler flag. When enabled, null and undefined become distinct types and cannot be assigned to objects or primitives, preventing "Cannot read property of null" crashes.
3. Explain the concept of Type Erasure.
Type Erasure means that all TypeScript-specific syntax (interfaces, type aliases, generics, public/private modifiers) is completely removed during compilation. The resulting JavaScript has zero knowledge of the types. This means TS provides absolutely no runtime validation; you must use tools like Zod or Joi to validate incoming API requests at runtime.
4. How does tsconfig.json impact a Monorepo build time?
In large Monorepos, compiling the entire project at once causes Out Of Memory crashes. We solve this using Project References. By setting "composite": true in the library packages and using the "references" array in the dependent applications, tsc --build acts incrementally. It caches build signatures in .tsbuildinfo files and only recompiles packages whose public API actually changed.
5. Covariance vs Contravariance in TypeScript
- Covariance: A type can be safely replaced by a narrower (more specific) type. If a function returns
Animal, it is safe for it to returnDog. (Return types are covariant). - Contravariance: A type can be safely replaced by a wider (more general) type. If a function accepts a
Dogas an argument, it is NOT safe to pass it a function that expects anAnimal(because the function might callanimal.meow()). (Function arguments are contravariant).
6. What are the performance implications of complex types?
Heavy use of deeply nested Recursive Types, Conditional Types, and Template Literal Types forces the TypeScript compiler to do massive amounts of mathematical cross-product calculations on every keystroke in the IDE. This can cause the Language Server to lag intensely and compilation times to skyrocket. Senior developers must balance “perfect type safety” with “developer experience.”
7. When should you use any?
Ideally, never. any turns off the type checker completely. If you are migrating a massive legacy JS app to TS, you might use it temporarily. If you are accepting truly dynamic data (like an API response), you should use unknown, which forces the developer to write a runtime Type Guard before accessing the data.