Skip to content
Bill Liao
Go back

100 TypeScript interview Questions and Answers

Edit page

Below is a practical TypeScript interview guide, organized from fundamentals to advanced topics. The answers are intentionally concise enough for interview revision while still giving you the key concepts interviewers expect.


1. TypeScript Fundamentals

1. What is TypeScript?

Answer:
TypeScript is a statically typed superset of JavaScript developed by Microsoft. It adds features such as:

TypeScript code is compiled/transpiled into JavaScript that can run in browsers, Node.js, or other JavaScript environments.


2. Why use TypeScript instead of JavaScript?

Answer:

The main advantages are:

For example:

function add(a: number, b: number): number {
  return a + b;
}

add(10, "20"); // Compile-time error

3. Is TypeScript statically typed or dynamically typed?

Answer:
TypeScript provides static type checking, but the generated JavaScript remains dynamically typed at runtime.

TypeScript checks:

TypeScript

let age: number = 30;

But after compilation, JavaScript doesn’t retain TypeScript’s type annotations.


4. Does TypeScript run directly in the browser?

Answer:
Normally, no.

Browsers execute JavaScript. TypeScript must first be transpiled into JavaScript.

Typical process:

TypeScript
    ↓
TypeScript Compiler (tsc)
    ↓
JavaScript
    ↓
Browser / Node.js

5. What is the TypeScript compiler?

Answer:
The TypeScript compiler is commonly invoked using tsc.

Example:

Bash

tsc app.ts

It converts TypeScript into JavaScript according to the project’s compiler configuration.


6. What is tsconfig.json?

Answer:
tsconfig.json defines TypeScript compiler configuration for a project.

Example:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "strict": true,
    "outDir": "./dist"
  },
  "include": ["src"]
}

7. What does "strict": true do?

Answer:
It enables a collection of strict type-checking options.

Important checks include:

It is strongly recommended for production TypeScript projects.


8. What is type inference?

Answer:
TypeScript can automatically determine a variable’s type without an explicit annotation.

let name = "Bill";
let age = 55;

TypeScript infers:

name: string
age: number

9. What is type annotation?

Answer:
A type annotation explicitly specifies a variable’s type.

let age: number = 30;

function greet(name: string): string {
  return `Hello ${name}`;
}

10. What is the difference between inference and annotation?

Answer:

let age = 30;       // inference
let count: number = 30; // annotation

Inference is usually preferred when TypeScript can determine the type clearly.


2. TypeScript Basic Types

11. What are the primitive types in TypeScript?

Answer:

Common primitive types include:

string
number
boolean
bigint
symbol
null
undefined

There are also special types such as:

any
unknown
never
void
object

12. What is any?

Answer:
any disables most type checking for a value.

let value: any = 10;

value = "hello";
value = true;
value.foo.bar();

It should generally be avoided because it removes TypeScript’s safety.


13. What is unknown?

Answer:
unknown represents a value whose type is not yet known.

Unlike any, you must narrow the value before using it.

let value: unknown = "hello";

if (typeof value === "string") {
  console.log(value.toUpperCase());
}

Interview point: Prefer unknown over any when receiving untrusted or dynamic data.


14. any vs unknown?

Answer:

anyunknown
Disables type checkingPreserves type safety
Can access properties directlyRequires narrowing
DangerousSafer
Avoid when possiblePreferred for unknown data

15. What is never?

Answer:
never represents values that can never occur.

For example:

function fail(message: string): never {
  throw new Error(message);
}

It is also useful for exhaustive checks.


16. What is void?

Answer:
void generally represents a function that doesn’t return a meaningful value.

function logMessage(message: string): void {
  console.log(message);
}

17. What is null vs undefined?

Answer:

With strict null checking enabled, they are distinct types.


18. What is the object type?

Answer:
object represents non-primitive values.

let user: object = {
  name: "Bill"
};

It does not mean “any JavaScript object with arbitrary properties.”


19. What is a tuple?

Answer:
A tuple represents an array with a fixed structure and known element types.

TypeScript

let user: [string, number] = ["Bill", 55];

The first element must be a string and the second a number.


20. What is an array type?

Answer:

Two common syntaxes are:

let numbers: number[] = [1, 2, 3];

let names: Array<string> = ["Bill", "John"];

Both represent arrays containing values of the specified type.


3. Interfaces and Type Aliases

21. What is an interface?

Answer:
An interface defines the structure that an object should satisfy.

interface User {
  id: number;
  name: string;
  email: string;
}

const user: User = {
  id: 1,
  name: "Bill",
  email: "bill@example.com"
};

22. What is a type alias?

Answer:
A type alias gives a name to a type.

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

It can represent more than object structures.

TypeScript

type ID = string | number;

23. Interface vs type alias?

Answer:

InterfaceType
Excellent for object contractsMore flexible
Supports declaration mergingDoes not normally merge
Can be extendedCan use intersections
Commonly used for public object APIsUseful for unions, tuples, primitives

Example:

interface User {
  name: string;
}

type ID = string | number;

24. Can an interface extend another interface?

Answer:
Yes.

interface Person {
  name: string;
}

interface Employee extends Person {
  employeeId: number;
}

25. Can a type extend another type?

Answer:
Type aliases use intersections.

type Person = {
  name: string;
};

type Employee = Person & {
  employeeId: number;
};

26. What is declaration merging?

Answer:
TypeScript can merge multiple declarations with the same interface name.

interface User {
  name: string;
}

interface User {
  age: number;
}

The resulting interface contains both:

interface User {
  name: string;
  age: number;
}

27. Can interfaces describe functions?

Answer:
Yes.

interface Calculator {
  (a: number, b: number): number;
}

const add: Calculator = (a, b) => a + b;

28. What is an optional property?

Answer:
Use ?.

interface User {
  name: string;
  age?: number;
}

age may be absent.


29. What is a readonly property?

Answer:

interface User {
  readonly id: number;
}

The property cannot normally be reassigned after initialization.


30. Does readonly make an object deeply immutable?

Answer:
No.

interface User {
  readonly profile: {
    name: string;
  };
}

You cannot replace profile, but you can still modify:

TypeScript

user.profile.name = "John";

unless the nested structure is also readonly.


4. Union, Intersection and Literal Types

31. What is a union type?

Answer:
A union allows a value to have one of several types.

let id: string | number;

id = "ABC";
id = 123;

32. What is an intersection type?

Answer:
An intersection combines multiple types.

type Person = {
  name: string;
};

type Employee = {
  employeeId: number;
};

type Staff = Person & Employee;

Staff must have both properties.


33. Union vs intersection?

Answer:

TypeScript

A | B

means A OR B.

TypeScript

A & B

means A AND B.


34. What are literal types?

Answer:
Literal types restrict a value to specific values.

TypeScript

type Status = "pending" | "approved" | "rejected";

This prevents invalid values:

TypeScript

let status: Status = "approved";

35. What are discriminated unions?

Answer:
They are unions that share a common discriminating property.

type Success = {
  status: "success";
  data: string;
};

type Failure = {
  status: "error";
  error: string;
};

type Result = Success | Failure;

Then:

function handle(result: Result) {
  if (result.status === "success") {
    console.log(result.data);
  } else {
    console.log(result.error);
  }
}

They are extremely useful for state modeling.


5. Functions

36. How do you type a function?

Answer:

function add(a: number, b: number): number {
  return a + b;
}

37. How do you type arrow functions?

Answer:

const add = (a: number, b: number): number => {
  return a + b;
};

38. What are optional parameters?

Answer:

function greet(name: string, title?: string) {
  // ...
}

The second parameter is optional.


39. What are default parameters?

Answer:

function greet(name: string = "Guest") {
  return `Hello ${name}`;
}

40. What are rest parameters?

Answer:

function sum(...numbers: number[]): number {
  return numbers.reduce((a, b) => a + b, 0);
}

41. What is function overload?

Answer:
Function overloads allow multiple call signatures for one implementation.

function format(value: string): string;
function format(value: number): string;

function format(value: string | number): string {
  return String(value);
}

42. Why use function overloads?

Answer:
They provide more precise APIs when different input types have different valid behaviors.

The implementation signature is generally broader than the overload signatures.


43. What is a callback type?

Answer:

function process(
  value: number,
  callback: (result: number) => void
) {
  callback(value * 2);
}

44. What is contextual typing?

Answer:
TypeScript can infer a function parameter’s type from context.

const numbers: number[] = [1, 2, 3];

numbers.map(n => n * 2);

TypeScript knows n is a number.


45. What is a function type?

Answer:

type Operation = (a: number, b: number) => number;

const multiply: Operation = (a, b) => a * b;

6. Classes and Object-Oriented TypeScript

46. Does TypeScript support classes?

Answer:
Yes. It provides JavaScript classes plus additional type-system features.

class User {
  constructor(
    public name: string,
    private age: number
  ) {}
}

47. What are access modifiers?

Answer:

TypeScript supports:

Example:

class User {
  public name: string;
  private password: string;
  protected id: number;
}

48. What is private?

Answer:
A private member can only be accessed within the declaring class.

class User {
  private password = "secret";
}

49. What is protected?

Answer:
A protected member can be accessed within the class and subclasses.

class Animal {
  protected name: string = "Animal";
}

class Dog extends Animal {
  printName() {
    console.log(this.name);
  }
}

50. What is public?

Answer:
public members can be accessed from anywhere.

It is also the default accessibility modifier.


51. What is abstract?

Answer:
An abstract class cannot be instantiated directly.

abstract class Animal {
  abstract makeSound(): void;
}

A subclass must implement the abstract member.


52. Interface vs abstract class?

Answer:

Interface:

Abstract class:


53. Does TypeScript support multiple inheritance?

Answer:
Classes cannot extend multiple classes.

TypeScript

class C extends A, B {} // Invalid

But a class can implement multiple interfaces:

class Employee implements Person, Auditable {
}

54. What is implements?

Answer:
implements checks whether a class satisfies an interface.

interface Printable {
  print(): void;
}

class Report implements Printable {
  print() {
    console.log("Report");
  }
}

55. What is extends?

Answer:
extends establishes inheritance.

class Dog extends Animal {
}

It can also be used with interfaces and certain type constructs.


7. Generics

56. What are generics?

Answer:
Generics allow reusable code to work with different types while preserving type safety.

function identity<T>(value: T): T {
  return value;
}

const result = identity<string>("Hello");

57. Why use generics instead of any?

Answer:
any loses type information.

function identity(value: any): any {
  return value;
}

Generics preserve the relationship between input and output:

function identity<T>(value: T): T {
  return value;
}

58. What are generic constraints?

Answer:
Constraints restrict what types can be passed to a generic.

function getLength<T extends { length: number }>(value: T) {
  return value.length;
}

59. Can interfaces use generics?

Answer:
Yes.

interface ApiResponse<T> {
  data: T;
  success: boolean;
}

const response: ApiResponse<User> = {
  data: user,
  success: true
};

60. Can classes use generics?

Answer:
Yes.

class Repository<T> {
  private items: T[] = [];

  add(item: T) {
    this.items.push(item);
  }
}

61. What is keyof?

Answer:
keyof produces a union of an object’s property names.

interface User {
  id: number;
  name: string;
}

type UserKey = keyof User;

Equivalent to:

TypeScript

"id" | "name"

62. What is generic K extends keyof T?

Answer:
It ensures that K is a valid property key of T.

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

This is a common advanced TypeScript pattern.


8. Type Narrowing

63. What is type narrowing?

Answer:
Type narrowing means reducing a broad type to a more specific type based on runtime checks.

function print(value: string | number) {
  if (typeof value === "string") {
    console.log(value.toUpperCase());
  } else {
    console.log(value.toFixed(2));
  }
}

64. What is a type guard?

Answer:
A type guard is a runtime check that allows TypeScript to narrow a type.

Examples:

typeof
instanceof
in

65. What is typeof narrowing?

Answer:

function process(value: string | number) {
  if (typeof value === "string") {
    return value.toUpperCase();
  }

  return value.toFixed(2);
}

66. What is instanceof narrowing?

Answer:

if (error instanceof Error) {
  console.log(error.message);
}

TypeScript understands that error is an Error inside the block.


67. What is the in operator used for?

Answer:
It can narrow unions based on whether a property exists.

if ("email" in user) {
  console.log(user.email);
}

68. What is a user-defined type guard?

Answer:
A function can explicitly tell TypeScript what type a value is.

function isString(value: unknown): value is string {
  return typeof value === "string";
}

Then:

if (isString(value)) {
  value.toUpperCase();
}

69. What is an exhaustive check?

Answer:
It ensures all possible union cases have been handled.

function assertNever(value: never): never {
  throw new Error(`Unexpected value: ${value}`);
}

This is especially useful with discriminated unions.


9. Type Assertions and Advanced Types

70. What is a type assertion?

Answer:
A type assertion tells TypeScript how you want it to treat a value.

TypeScript

const value = input as string;

It does not perform runtime conversion.


71. as vs type conversion?

Answer:

TypeScript

const value = input as string;

doesn’t convert anything.

For actual conversion:

TypeScript

const value = String(input);

72. What is the non-null assertion operator !?

Answer:

TypeScript

const element = document.getElementById("app")!;

It tells TypeScript that the value isn’t null or undefined.

It should be used carefully because it provides no runtime protection.


73. What is as const?

Answer:
as const creates readonly literal types.

const config = {
  environment: "production",
  port: 8080
} as const;

The values are inferred as:

environment: "production"
port: 8080

rather than general string and number.


74. What is the satisfies operator?

Answer:
satisfies checks that an expression conforms to a type without unnecessarily widening its inferred type.

type Config = {
  mode: "dev" | "prod";
};

const config = {
  mode: "prod"
} satisfies Config;

This is particularly useful for configuration objects.


75. What are conditional types?

Answer:
Conditional types select one type based on a condition.

type IsString<T> =
  T extends string ? true : false;

Example:

TypeScript

type Result = IsString<string>; // true

76. What are mapped types?

Answer:
Mapped types create new types by transforming properties of an existing type.

type ReadonlyUser<T> = {
  readonly [P in keyof T]: T[P];
};

77. What are template literal types?

Answer:
They allow types to be constructed using template literal syntax.

TypeScript

type EventName = `on${"Click" | "Hover"}`;

Result:

TypeScript

"onClick" | "onHover"

78. What is infer?

Answer:
infer allows TypeScript to infer a type inside a conditional type.

Example:

type ReturnTypeOf<T> =
  T extends (...args: any[]) => infer R
    ? R
    : never;

R represents the inferred return type.


10. Utility Types

79. What is Partial<T>?

Answer:
It makes all properties optional.

interface User {
  name: string;
  age: number;
}

type PartialUser = Partial<User>;

Equivalent conceptually to:

{
  name?: string;
  age?: number;
}

80. What is Required<T>?

Answer:
It makes all properties required.

TypeScript

type RequiredUser = Required<User>;

81. What is Readonly<T>?

Answer:
It makes all properties readonly.

TypeScript

type ReadonlyUser = Readonly<User>;

82. What is Pick<T, K>?

Answer:
It creates a type containing selected properties.

TypeScript

type UserSummary = Pick<User, "name" | "age">;

83. What is Omit<T, K>?

Answer:
It creates a type excluding selected properties.

TypeScript

type PublicUser = Omit<User, "password">;

84. What is Record<K, T>?

Answer:
It creates an object type whose keys are K and values are T.

type UserRoles = Record<string, string>;

const roles: UserRoles = {
  bill: "admin",
  john: "user"
};

85. What is Exclude<T, U>?

Answer:
It removes types from a union.

type Status = "success" | "error" | "loading";

type Finished = Exclude<Status, "loading">;

Result:

TypeScript

"success" | "error"

86. What is Extract<T, U>?

Answer:
It keeps only union members assignable to another type.

TypeScript

type A = Extract<"a" | "b" | "c", "a" | "c">;

Result:

TypeScript

"a" | "c"

87. What is NonNullable<T>?

Answer:
It removes null and undefined.

TypeScript

type Value = NonNullable<string | null | undefined>;

Result:

TypeScript

string

88. What is ReturnType<T>?

Answer:
It extracts the return type of a function.

function getUser() {
  return {
    id: 1,
    name: "Bill"
  };
}

type User = ReturnType<typeof getUser>;

89. What is Parameters<T>?

Answer:
It extracts a function’s parameters as a tuple.

function add(a: number, b: string) {}

type Args = Parameters<typeof add>;

Result:

TypeScript

[number, string]

11. Modules and TypeScript Architecture

90. What is the difference between type and interface for API design?

Answer:
Both can describe object contracts, but they have different strengths.

For public object-oriented APIs, interfaces are often convenient because they support extension and declaration merging.

For advanced composition such as:

type ID = string | number;

type Response<T> =
  Success<T> | Failure;

type aliases are generally more flexible.


91. What are ES modules in TypeScript?

Answer:
TypeScript supports standard JavaScript modules.

export class UserService {
}

Then:

TypeScript

import { UserService } from "./UserService";

92. What is the difference between import and import type?

Answer:

TypeScript

import { User } from "./types";

can potentially represent a runtime import depending on how it’s used/configured.

TypeScript

import type { User } from "./types";

explicitly indicates that the import is type-only and should not be emitted as a runtime dependency.


93. What is a .d.ts file?

Answer:
A .d.ts file contains TypeScript declarations without implementation.

For example:

declare function calculate(
  a: number,
  b: number
): number;

Declaration files allow TypeScript to understand JavaScript libraries and APIs.


94. How does TypeScript work with JavaScript libraries?

Answer:
It can obtain type information from:

  1. Built-in declarations
  2. Library-provided .d.ts files
  3. Community type packages
  4. Custom declaration files

Historically, many community declarations were published through @types/* packages.


12. Advanced Interview Questions

95. What is structural typing?

Answer:
TypeScript primarily uses structural typing.

Compatibility depends on the shape of the types rather than their explicit names.

interface Person {
  name: string;
}

const employee = {
  name: "Bill",
  id: 123
};

const person: Person = employee;

This works because employee has the required structure.


96. What is covariance and contravariance?

Answer:
They describe how type relationships behave when types are nested, particularly with functions and generic structures.

A simplified interview explanation:

This becomes important when designing callback APIs and generic abstractions.


97. What is the difference between compile-time and runtime type safety?

Answer:
TypeScript primarily provides compile-time type checking.

For example:

interface User {
  name: string;
}

doesn’t automatically validate JSON received from an API at runtime.

If an API returns malformed data, TypeScript’s compile-time types don’t magically validate it.

For runtime validation, you need explicit validation logic or a schema-validation library.

Key interview point:

TypeScript types are erased from the emitted JavaScript.


98. How would you safely handle API responses in TypeScript?

Answer:
Don’t blindly trust an API response just because you declared a TypeScript type.

For example:

interface User {
  id: number;
  name: string;
}

This:

TypeScript

const user = await response.json() as User;

is only a compile-time assertion.

A production application should validate untrusted external data at runtime and then work with the validated type.

A robust architecture is:

External API
     ↓
Unknown Data
     ↓
Runtime Validation
     ↓
Validated Type
     ↓
Business Logic

99. What are common TypeScript mistakes in large projects?

Answer:

Common problems include:

  1. Overusing any
  2. Excessive type assertions
  3. Using ! everywhere
  4. Ignoring strict mode
  5. Duplicating types
  6. Creating overly complicated generic types
  7. Trusting external data without validation
  8. Mixing domain types with API DTOs
  9. Using enums when literal unions are simpler
  10. Treating TypeScript types as runtime validation

A good TypeScript codebase balances type safety, readability, and maintainability.


100. What are the most important TypeScript best practices?

Answer:

For production applications:

1. Enable strict mode
2. Prefer inference where obvious
3. Avoid any
4. Use unknown for untrusted values
5. Model domain states with discriminated unions
6. Use generics for reusable type-safe abstractions
7. Prefer type narrowing over unsafe assertions
8. Validate external data at runtime
9. Keep types close to their domain
10. Avoid unnecessarily complex type-level programming
11. Use readonly where appropriate
12. Keep compiler configuration consistent
13. Use utility types instead of duplicating types
14. Make APIs explicit and predictable
15. Treat TypeScript as a design tool, not just an error checker

⭐ 20 TypeScript Questions You Should Definitely Master

If you’re preparing for a Senior / Lead Full-Stack Developer interview, I would prioritize these:

#TopicInterview Importance
1any vs unknown⭐⭐⭐⭐⭐
2never vs void⭐⭐⭐⭐
3Interface vs type⭐⭐⭐⭐⭐
4Union vs intersection⭐⭐⭐⭐⭐
5Type narrowing⭐⭐⭐⭐⭐
6Type guards⭐⭐⭐⭐⭐
7Generics⭐⭐⭐⭐⭐
8Generic constraints⭐⭐⭐⭐⭐
9keyof⭐⭐⭐⭐⭐
10typeof⭐⭐⭐⭐
11Conditional types⭐⭐⭐⭐⭐
12Mapped types⭐⭐⭐⭐⭐
13infer⭐⭐⭐⭐
14Utility types⭐⭐⭐⭐⭐
15Partial / Pick / Omit⭐⭐⭐⭐⭐
16ReturnType / Parameters⭐⭐⭐⭐
17as const⭐⭐⭐⭐
18satisfies⭐⭐⭐⭐⭐
19Structural typing⭐⭐⭐⭐⭐
20Runtime vs compile-time validation⭐⭐⭐⭐⭐

🎯 Senior-Level Interview Tip

For a Senior/Lead TypeScript interview, don’t stop at definitions.

Interviewers increasingly ask questions like:

“How would you design this API so that invalid states are impossible to represent?”

or:

“How would you safely type an API response that you don’t control?”

or:

“When would you choose a discriminated union over an inheritance hierarchy?”

or:

“Can you design a generic repository that preserves type safety?”

The strongest answers connect TypeScript features to real software architecture, API design, maintainability, and runtime boundaries—not just syntax.


Edit page
Share this post:

Previous Post
100 Node.js interview Questions and Answers
Next Post
100 JavaScript interview Questions and Answers