Real World Example

CRUD DTOs From One Entity

Backend teams (NestJS services at fintechs, Next.js admin panels) derive all their request and response types from one entity type. Add a field once and every DTO updates.

Example

type Product = {
  id: number;
  name: string;
  description: string;
  price: number;
  stock: number;
  category: "electronics" | "books" | "fashion";
  createdAt: string;
};

type CreateProductDto = Omit<Product, "id" | "createdAt">;
type UpdateProductDto = Partial<CreateProductDto>;
type ProductListItem = Pick<Product, "id" | "name" | "price">;
type StockByCategory = Record<Product["category"], number>;

const db: Product[] = [];
let nextId = 1;

function create(dto: CreateProductDto): Product {
  const p: Product = { ...dto, id: nextId++, createdAt: "2026-01-15T10:00:00Z" };
  db.push(p);
  return p;
}
function update(id: number, dto: UpdateProductDto): Readonly<Product> | undefined {
  const p = db.find((x) => x.id === id);
  return p && Object.assign(p, dto);
}
const list = (): ProductListItem[] => db.map(({ id, name, price }) => ({ id, name, price }));

create({ name: "Kettle", description: "1.5L", price: 1299, stock: 10, category: "electronics" });
create({ name: "Atomic Habits", description: "Book", price: 499, stock: 40, category: "books" });
update(1, { price: 1199 });

const stock: StockByCategory = { electronics: 0, books: 0, fashion: 0 };
db.forEach((p) => (stock[p.category] += p.stock));
console.log(list());
console.log(stock);

Output

[
  { id: 1, name: 'Kettle', price: 1199 },
  { id: 2, name: 'Atomic Habits', price: 499 }
]
{ electronics: 10, books: 40, fashion: 0 }