0Pricing
TypeScript Academy · Lección

Modelado de dominio: agregados, invariantes y servicios

Modele agregados como Cart con IDs branded y garantice invariantes mediante fábricas y servicios.

Modelado de dominio: agregados, invariantes y servicios es una lección gratuita de TypeScript Academy en CoddyKit. Esta es la lección 3 de 3. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de TypeScript Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de TypeScript Academy incluye 3 lecciones en total.

Introducción

Objetivo: Modele un agregado Cart utilizando IDs con marca y asegúrese de que las reglas, como qty > 0, se cumplan en las fábricas y los servicios.

  • Los IDs con marca distinguen los límites entre entidades
  • Las fábricas devuelven uniones Result
  • Las funciones de servicio evitan transiciones no válidas

Entidades y marcas

Los IDs con marca hacen que CartId y ProductId sean incompatibles aunque ambos sean cadenas. Esto evita confusiones.

type Brand<Tag extends string, T> = T & { readonly __brand: Tag }

type CartId = Brand<"CartId", string>
type ProductId = Brand<"ProductId", string>

type Result<T> = { ok: true; value: T } | { ok: false; error: string }

const cartId = (s: string): CartId => s as CartId
const productId = (s: string): ProductId => s as ProductId

Agregado e invariante

Las fábricas validan las reglas: qty debe ser > 0. Solo se pueden crear objetos Line válidos.

type Money = number & { readonly __brand: "Money" }
const money = (n: number): Money => n as Money

interface Line { productId: ProductId; qty: number; price: Money }
interface Cart { id: CartId; lines: Line[]; total: Money }

function makeLine(productId: ProductId, qty: number, price: Money): Result<Line> {
  if (!Number.isInteger(qty) || qty <= 0) return { ok: false, error: "qty must be > 0" }
  return { ok: true, value: { productId, qty, price } }
}

function makeCart(id: CartId): Cart { return { id, lines: [], total: money(0) } }

Servicio: añadir artículo

Las funciones de servicio realizan transiciones seguras y vuelven a calcular los totales. Si los totales no son válidos, la función devuelve un error en lugar de corromper el estado.

function addItem(cart: Cart, line: Line): Result<Cart> {
  const lines = [...cart.lines, line]
  const totalNum = lines.reduce((s, x) => s + (x.qty * (x.price as number)), 0)
  if (!Number.isFinite(totalNum) || totalNum < 0) return { ok: false, error: "invalid total" }
  return { ok: true, value: { ...cart, lines, total: (totalNum as unknown) as Money } }
}

// Usage
const c0 = makeCart(cartId("c1"))
const l = makeLine(productId("p1"), 2, money(10))
const c1 = l.ok ? addItem(c0, l.value) : { ok: false, error: "bad line" }

Mapeo en los límites

En los límites del sistema (por ejemplo, las API), convierta los datos a DTO y valídelos al analizarlos de nuevo. Las fábricas garantizan que los datos sean correctos.

type CartDTO = { id: string; lines: { productId: string; qty: number; price: number }[]; total: number }

function serialize(c: Cart): CartDTO {
  return {
    id: c.id as unknown as string,
    lines: c.lines.map(x => ({ productId: x.productId as unknown as string, qty: x.qty, price: x.price as unknown as number })),
    total: c.total as unknown as number
  }
}

function parse(dto: CartDTO): Result<Cart> {
  const id = cartId(dto.id)
  const lines: Line[] = []
  for (const raw of dto.lines) {
    const l = makeLine(productId(raw.productId), raw.qty, money(raw.price))
    if (!l.ok) return { ok: false, error: l.error }
    lines.push(l.value)
  }
  const totalNum = lines.reduce((s, x) => s + (x.qty * (x.price as number)), 0)
  return { ok: true, value: { id, lines, total: money(totalNum) } }
}

Consejos

Prácticas recomendadas:

  • Centralice la validación en las fábricas.
  • Mantenga las funciones de servicio puras y deterministas.
  • Realice conversiones de marcas únicamente en los límites del sistema.

Comprobación de invariantes

Comprobación rápida: ¿Cómo debe imponer una invariante como qty > 0?

Repaso

Repaso: Los IDs con marca, combinados con fábricas y servicios, imponen invariantes. No se pueden crear estados no válidos porque todos los puntos de entrada validan los datos.

Preguntas frecuentes

¿La lección «Modelado de dominio: agregados, invariantes y servicios» es gratis?

Sí — el texto completo de «Modelado de dominio: agregados, invariantes y servicios» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de TypeScript Academy, actualiza a CoddyKit PRO. El curso de TypeScript Academy incluye 3 lecciones en total.

¿Qué aprenderé en «Modelado de dominio: agregados, invariantes y servicios»?

Modele agregados como Cart con IDs branded y garantice invariantes mediante fábricas y servicios. Practicas TypeScript Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar TypeScript Academy?

No se requiere experiencia previa. TypeScript Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 3.

¿Cuánto tiempo toma la lección «Modelado de dominio: agregados, invariantes y servicios»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de TypeScript Academy?

Sí. Cada lección de TypeScript Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Tipos branded/opacos para evitar confusiones entre unidades
  2. IDs etiquetados y patrones de modelado de dominio
  3. Modelado de dominio: agregados, invariantes y servicios
← Volver a TypeScript Academy