TypeScript interviews probe static typing, inference, generics, and how types compile away while shaping runtime-safe APIs.
15 TypeScript Interview Questions with Answers
Use the short version first, then offer trade-offs if the interviewer wants depth.
1. What is TypeScript and what problem does it solve?
TypeScript is a typed superset of JavaScript that adds optional static types, interfaces, enums, and compile-time checking. It catches category errors before runtime, improves IDE autocomplete and refactoring, and documents contracts in large codebases. Output is plain JavaScript via tsc or bundlers.
2. Difference between interface and type alias?
Both describe object shapes and can be extended. Interfaces support declaration merging (multiple declarations merge), which is useful for augmenting third-party modules. Type aliases can represent unions, tuples, primitives, and mapped types interfaces cannot express as cleanly. Prefer interfaces for public object APIs; types for unions and utilities.
3. What is type inference?
The compiler deduces types when you omit annotations—const x = 1 yields number literal or number depending on context. Function return types are inferred from return statements. Lean on inference for locals; annotate exported function parameters and public APIs for stable contracts.
4. Explain structural typing in TypeScript.
TypeScript uses structural (duck) typing: if an object has the required properties with compatible types, it matches the type regardless of name. Two interfaces with identical shapes are assignable to each other. This differs from nominal typing in languages like Java and affects how you design API boundaries.
5. What is the difference between any and unknown?
any disables type checking for that value—you can call anything on it. unknown is the type-safe top type: you must narrow or assert before use. Prefer unknown for external data (JSON.parse results) and reserve any only for gradual migration with eslint rules limiting spread.
6. How does type narrowing work?
Control flow analysis refines types after checks: typeof x === "string", x instanceof Date, "id" in obj, or discriminated unions with a kind/tag field. Switch statements and early returns help the compiler understand which branch you are in.
7. What are generics and why use them?
Generics parameterize types so functions and classes work across types while staying type-safe: function identity<T>(value: T): T. Constraints like T extends { id: string } limit acceptable types. They avoid duplication and any while preserving relationships between inputs and outputs.
8. Difference between enum and union of string literals?
String literal unions like type Status = "idle" | "loading" have no runtime artifact and tree-shake cleanly. Enums generate JavaScript objects and can surprise you with reverse mappings for numeric enums. Modern codebases often prefer as const objects or unions unless interop requires enums.
9. What does strict mode enable in tsconfig?
strict turns on strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitAny, noImplicitThis, and alwaysStrict. It catches null/undefined bugs, loose function types, and implicit any. Teams enabling strict incrementally often use strictNullChecks first.
10. Explain the satisfies operator.
const config = { host: "api.example.com", port: 443 } satisfies ServerConfig validates against ServerConfig without widening literal types to string/number. Unlike as ServerConfig, satisfies preserves narrow literals for autocomplete while still erroring on missing or wrong keys.
11. What are utility types Pick, Omit, Partial, and Record?
Pick<T, K> selects keys; Omit<T, K> removes them. Partial<T> makes all properties optional—handy for update DTOs. Record<K, V> builds an object type with keys K and values V. These compose for API layers without duplicating interface definitions.
12. How do you type a function that might throw vs return?
TypeScript return types describe successful returns only; thrown errors are not in the union unless you model Result types manually. For expected failures, return { ok: true, data } | { ok: false, error } or use libraries like neverthrow. Document thrown exceptions in JSDoc for consumers.
13. What is declaration merging and module augmentation?
Interfaces with the same name in the same scope merge declarations—useful for extending Express Request or global Window. Module augmentation adds types to imported modules: declare module "express-serve-static-core" { interface Request { user?: User } }.
14. How would you migrate a large JavaScript codebase to TypeScript?
Enable allowJs and checkJs, add a tsconfig with incremental strictness, rename files gradually, and type boundaries first (API modules, shared utils). Use unknown for external input, avoid mass any, and enforce noImplicitAny in CI once coverage is sufficient. @types packages cover many libraries.
15. What are conditional types and when are they useful?
Conditional types choose one type or another based on a condition: T extends U ? X : Y. They power advanced utilities like Exclude, Extract, and infer in template literal types. Use them in library typings—not everyday app code—when inference must depend on generic parameters.
Pro Tip
When asked a typing puzzle, talk through inference out loud—interviewers care about reasoning, not memorizing utility type syntax.