Onjsdev Logo
Typescript Generics
23 Jun 20252 min read
TypescriptGenerics

Typescript Generics


TypeScript Generics might seem complex at first glance—but once you understand them, they become one of the most powerful way for ensuring type safety in your code.

They let you write flexible, type-safe code that adapts to a variety of use cases. Whether you're building a utility function, a React component, or an API wrapper, knowing how and when to use generics will level up your TypeScript code instantly.

What Are Generics, Really?

At their core, generics are placeholders for types—just like function parameters are placeholders for values.

Regular Function:

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

Generic Function:

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

The <T> here says: “This function works with any type T, and whatever goes in must come out as the same type.” Now identity(123) returns a number, and identity("hello") returns a string—with full type safety.

Practical Use Cases

Imagine a function to get the first item of an array. The array can include any type of items including numbers, strings, objects, etc. So it is better to use a generic type to represent it.

function first<T>(arr: T[]): T | undefined {
  return arr[0];
}

This function now works safely with any array number[], string[], even complex object arrays.

const nums = first([1, 2, 3]); // number
const words = first(["a", "b"]); // string

Generic Interfaces and Types

You can build reusable data structures that work with any type. This is very useful while working with APIs.

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

Used like this:

const userResponse: ApiResponse<{ name: string }> = {
  data: { name: "Alice" },
  success: true,
};

This way, you can use the ApiResponse type for any API response that returns a data property of type T.

Generic React Components

React components can be generic too. This allows you to create reusable components that work with any type of data.

type ListProps<T> = {
  items: T[];
  render: (item: T) => React.ReactNode;
};

function List<T>({ items, render }: ListProps<T>) {
  return <ul>{items.map(render)}</ul>;
}

Now List can render anything—users, posts, tags—without losing type safety.

Constraints and Defaults

Want to ensure a generic has certain properties? Use extends:

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

This lets you use .length safely on arrays, strings, or custom objects.

Default Types

You can provide fallback types too:

function wrapValue<T = string>(value: T): T[] {
  return [value];
}

const wrapped = wrapValue(42); // number[]
const defaultWrapped = wrapValue(); // string[]

This lets you create a generic function that works with any type, or a default type if no type is provided.

Keyof

The keyof operator is used to get the keys of an object. You can combine it with generics to create a function that works with any object.

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

This lets you get the value of a property of an object of type T with a key of type K.

Conclusion

TypeScript generics might look intimidating at first, but once you start applying them, you’ll wonder how you ever coded without them.

They offer the best of both worlds: reusability and strict typing. Whether you’re creating utility functions, structuring data responses, or writing clean UI components, generics help you write code that’s DRY, safe, and scalable.

Thank you for reading.