Interview Q&A / TypeScript

BeginnerIn-depth3 min readUpdated 2 Oct 2026

What are generics in TypeScript and why are they useful?

SHORT ANSWER

Generics let you write a function, class or type that works with many types while still remembering which type was used. Instead of falling back to any, you add a type parameter like T, so the output type is linked to the input type and TypeScript can still check your code.

Explain it simply

Think of a tiffin box. The same box can carry rice, roti or idli. When your mother packs idli in it, you know you will find idli when you open it at lunch. The box does not care what goes in, but it does not forget what went in either.

A generic is that tiffin box for types. You write the code once with a placeholder, usually called T, and TypeScript fills in the real type each time you use it. If you put a string in, you get a string out, and the editor knows it.

Without generics you have two bad choices: write the same function separately for numbers, strings and users, or use any, which throws away type checking.

Example

ts
// Without generics: works for anything, but the type is lost
function firstAny(items: any[]): any {
  return items[0];
}
const a = firstAny(["x", "y"]); // a is any, so a.toFixed() compiles and crashes

// With generics: the return type follows the input
function first<T>(items: T[]): T | undefined {
  return items[0];
}
const s = first(["x", "y"]); // s is string | undefined
const n = first([10, 20]);   // n is number | undefined

// Constraint: T must have a length property
function longest<T extends { length: number }>(a: T, b: T): T {
  return a.length >= b.length ? a : b;
}
longest("chai", "coffee");   // OK: strings have length
longest([1, 2], [1, 2, 3]);  // OK: arrays have length
// longest(10, 20);          // Error: number has no length

// keyof: the key must exist on the object, and the result type matches it
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
const user = { name: "Asha", age: 21 };
const age = getProp(user, "age"); // number
// getProp(user, "email");        // Error: "email" is not a key of user

// Generic types for API responses
interface ApiResponse<T> {
  data: T;
  error: string | null;
}
type UserResponse = ApiResponse<{ id: number; name: string }>;

How it works

  • <T> declares a type parameter. You can name it anything; T, K, V are conventions.
  • Usually TypeScript infers T from the arguments, so you rarely write first<string>(...). You can pass it explicitly when inference cannot work it out, like useState<User | null>(null) in React.
  • extends adds a constraint: "T can be any type, as long as it has these properties".
  • Generics exist only at compile time. They are erased in the JavaScript output, so you cannot check T at runtime.
  • Type parameters can have defaults: interface ApiResponse<T = unknown>.

Real-world use

  • Built-in types are generic: Array<T>, Promise<T>, Map<K, V>, Record<K, V>.
  • React: useState<T>, useRef<T>, and typed props for reusable components like a <Select<T>> dropdown.
  • API helpers: async function fetchJson<T>(url: string): Promise<T> so each call site gets a typed result.
  • Utility types such as Partial<T> and Pick<T, K> are themselves generics.

Common mistakes

  • Adding a type parameter that is used only once, like function log<T>(x: T): void. Plain unknown would do; generics are for linking types together.
  • Treating fetchJson<User>(url) as validation. It only tells the compiler what to expect; the server could still send something else. Validate untrusted data at runtime.
  • Writing T extends object when you actually need specific properties. Constrain to exactly what the function uses.
  • Trying to use T at runtime, like typeof T or new T(). Pass a value or a constructor instead.

What to say in the interview

"Generics let me write reusable code that works with many types without losing type information. I add a type parameter like T, and TypeScript usually infers it from the arguments, so the return type is tied to the input type. I can constrain it with extends, for example T extends { length: number }, and combine it with keyof to make safe property accessors. Arrays, Promises and React's useState are all generic. The key benefit over any is that the compiler still checks everything, and since generics are erased at compile time, they cost nothing at runtime."

Follow-up questions

  • What is a generic constraint and when do you need one?
  • How would you type a function that returns a property of an object given its key?
  • What is the difference between a generic and a union type?
  • How are utility types like Partial built using generics?

Go deeper

Read these once the basics above feel easy.

Generics power conditional types and mapped types. type ElementType<T> = T extends (infer U)[] ? U : T; pulls the element type out of an array type using infer. When a conditional type receives a union, it is applied to each member separately (it distributes), which is how built-ins like Exclude<T, U> work. A good rule from the TypeScript handbook: if a type parameter appears only once in a signature, you probably do not need it.

#generics#types#reusability

Related questions

Practise more TypeScript questions

Test your recall with short answers, then return to the detailed explanations when you need context.

Open TypeScript quick answers →

Get new questions like this by email

One short email when something new and useful lands. No spam, unsubscribe in one tap.

By subscribing you agree to the Privacy Policy.