Complete TypeScript Interview Questions & Answer Bank
75+ curated TypeScript interview questions covering core type primitives, structural typing, generics, utility types, mapped types, advanced type inference, decorators, and compiler optimization.
Q1: What is TypeScript and what are its core advantages over plain JavaScript?
TypeScript is a strongly typed, open-source programming language developed by Microsoft that builds on JavaScript by adding syntactical type declarations.
Core Advantages
- Static Type Checking: Catches errors at compile time rather than runtime.
- Enhanced IDE Support: Enables intelligent autocompletion, refactoring, and code navigation.
- Downlevel Compilation: Transpiles modern ECMAScript features down to older ES versions (ES5/ES3).
- Explicit Self-Documenting Code: Interfaces and type aliases act as living documentation.
- TypeScript is a strict syntactical superset of JavaScript.
- All valid JavaScript code is valid TypeScript code.
Q2: What is Structural Typing (Duck Typing) and how does it differ from Nominal Typing?
TypeScript uses a Structural Type System. Types are evaluated solely by their shape or structure (the properties and methods they possess), rather than their explicit declaration name or inheritance chain.
In Nominal Type Systems (like Java or C#), two objects with identical properties are not interchangeable unless they explicitly inherit from the same named class or interface.
interface Point2D { x: number; y: number; }
interface Vector2D { x: number; y: number; }
const logPoint = (p: Point2D) => console.log(`${p.x}, ${p.y}`);
const velocity: Vector2D = { x: 10, y: 20 };
logPoint(velocity); // Valid! Vector2D matches the structure of Point2D.- TypeScript checks structure, not explicit declaration names.
- If an object has the required fields with matching types, TypeScript considers it compatible.
Q3: What are the primitive types available in TypeScript?
TypeScript supports all native JavaScript primitives alongside type additions:
string: Textual data.number: Floating-point numbers and integers.boolean: True/false values.bigint: Large integers beyond $2^{53} - 1$.symbol: Unique, immutable identifiers.null&undefined: Absence of value or uninitialized state.void: Signals absence of return value from functions.
- Primitive types in TypeScript correspond directly to JavaScript's runtime primitive types.
- Always use lowercase primitive names (
string,number) rather than wrapper objects (String,Number).
Q4: What is the difference between `any` and `unknown` types?
any disables type checking entirely, turning off compile-time safety. You can access arbitrary properties, call them as functions, or assign them to any target type.
unknown is the type-safe counterpart of any. It represents any value, but TypeScript prevents you from performing arbitrary operations on an unknown variable until you perform explicit type checking or narrowing.
let valueAny: any = "hello";
valueAny.foo.bar(); // Compiles fine, runtime crash!
let valueUnknown: unknown = "hello";
// valueUnknown.trim(); // Error: Object is of type 'unknown'.
if (typeof valueUnknown === "string") {
console.log(valueUnknown.trim()); // Valid! Narrowed safely.
}- Prefer
unknownoveranywhen working with dynamic or unexpected values. unknownrequires explicit narrowing before property access.
Q5: What is the `never` type and how is it used for exhaustive type checking?
The never type represents values that never occur. It represents the return type of functions that never finish (e.g., throwing an error or running an infinite loop).
Because never is a assignable to every type, but no type is assignable to never (except never itself), it is used to perform Exhaustive Type Checking inside switch statements.
type Shape = { kind: 'circle' } | { kind: 'square' };
function getArea(s: Shape): number {
switch (s.kind) {
case 'circle': return Math.PI * 2;
case 'square': return 4;
default:
const _exhaustiveCheck: never = s;
return _exhaustiveCheck;
}
}neversignals unreachable code paths.- Assigning unhandled union cases to
neverguarantees total compile-time switch coverage.
Q6: What is the difference between `type` aliases and `interface` declarations?
Both type and interface define structural contracts, but they differ in capabilities:
Supported by `interface` | Unsupported by `type`Unsupported by `interface` | Supported by `type`A | B), primitives, tuples, and mapped types directly.`extends` keyword vs Intersection (`&`)- Use
interfacefor public API contracts and object structures that benefit from declaration merging. - Use
typefor union types, tuples, primitives, and complex mapped/conditional types.
Q7: What is the difference between Union Types (`|`) and Intersection Types (`&`)?
- Union Type (
A | B): Represents a value that can be either typeAor typeB. You can only access properties common to both types unless narrowed. - Intersection Type (
A & B): Combines multiple type structures into one. The resulting value must satisfy both type contracts simultaneously.
type Admin = { name: string; permissions: string[] };
type User = { name: string; email: string };
// Union: Must be Admin OR User
type Account = Admin | User;
// Intersection: Must have ALL properties from Admin AND User
type SuperAdmin = Admin & User;- Unions allow one of several types; Intersections merge multiple types into one.
Q8: What are Literal Types and how do `as const` assertions work?
Literal types restrict variables to exact concrete values (strings, numbers, or booleans) rather than wider primitive categories.
A const assertion (as const) instructs TypeScript to infer the narrowest possible literal types for object properties and arrays, turning properties into readonly fields.
// Standard object inference
const config = {
endpoint: "/api",
retries: 3
}; // Type: { endpoint: string; retries: number; }
// const assertion
const constConfig = {
endpoint: "/api",
retries: 3
} as const; // Type: { readonly endpoint: "/api"; readonly retries: 3; }- Literal types lock values to exact concrete constants.
as constcreates deeply immutable readonly literal data types.
Q9: What are Tuple Types in TypeScript and how do Readonly Tuples work?
A Tuple is a fixed-length array where every element index has an explicitly declared type.
Standard tuples permit mutable array operations like .push(), which can bypass tuple index checks. Wrapping tuples with readonly enforces strict immutability.
type ResponseState = [code: number, message: string];
const state: ResponseState = [200, "OK"];
type ImmutableState = readonly [number, string];
const fixed: ImmutableState = [404, "Not Found"];
// fixed.push("error"); // Error: Property 'push' does not exist on type 'readonly [number, string]'- Tuples lock array element types to explicit index positions.
- Use
readonlyon tuples to block accidental array mutations.
Q10: What are Enums, String Enums, and `const enum` declarations?
Enums allow defining named sets of constants. TypeScript supports Numeric, String, and const enums.
Standard enums generate runtime JavaScript objects. A const enum is completely removed during compilation—its values are directly inlined into call sites, leaving zero JavaScript runtime object footprint.
const enum Direction {
Up = "UP",
Down = "DOWN"
}
const move = Direction.Up;
// Compiled JS output:
// var move = "UP"; // No Enum object generated!- Use
const enumto eliminate runtime JavaScript object overhead. - String enums offer better readability during debugging than numeric enums.