0Pricing
TypeScript Academy · Lezione

Modellazione del dominio — aggregati, invarianti e servizi

Modelli aggregati come Cart con ID brandizzati e imponga gli invarianti tramite factory e servizi.

Modellazione del dominio — aggregati, invarianti e servizi è una lezione TypeScript Academy gratuita su CoddyKit. Questa è la lezione 3 di 3. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento TypeScript Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso TypeScript Academy include 3 lezioni in totale.

Introduzione

Obiettivo: modellare un aggregato Cart usando ID con brand e garantire che regole come qty > 0 vengano rispettate nelle factory e nei servizi.

  • Gli ID con brand distinguono i confini delle entità
  • Le factory restituiscono unioni Result
  • Le funzioni di servizio evitano transizioni non valide

Entità e brand

Gli ID con brand rendono CartId e ProductId incompatibili, anche se entrambi sono stringhe. Questo previene gli errori di associazione.

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

Aggregato e invariante

Le factory convalidano le regole: qty deve essere > 0. È possibile creare solo oggetti Line validi.

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) } }

Servizio: aggiungere un elemento

Le funzioni di servizio eseguono transizioni sicure e ricalcolano i totali. Se i totali non sono validi, la funzione restituisce un errore invece di corrompere lo stato.

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" }

Mappatura ai confini

Ai confini del sistema (ad es. nelle API), converta i dati in DTO e convalidi i dati quando li analizza nuovamente. Le factory garantiscono la correttezza dei dati.

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) } }
}

Suggerimenti

Buone pratiche:

  • Centralizzi la convalida nelle factory.
  • Mantenga le funzioni di servizio pure e deterministiche.
  • Esegua le conversioni dei brand solo ai confini del sistema.

Verifica dell'invariante

Verifica rapida: come si dovrebbe imporre un invariante come qty > 0?

Riepilogo

Riepilogo: gli ID con brand, combinati con factory e servizi, impongono gli invarianti. Non è possibile creare stati non validi perché tutti i punti d'ingresso convalidano l'input.

Domande Frequenti

La lezione «Modellazione del dominio — aggregati, invarianti e servizi» è gratuita?

Sì — il testo completo di «Modellazione del dominio — aggregati, invarianti e servizi» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso TypeScript Academy, passa a CoddyKit PRO. Il corso TypeScript Academy include 3 lezioni in totale.

Cosa imparerò in «Modellazione del dominio — aggregati, invarianti e servizi»?

Modelli aggregati come Cart con ID brandizzati e imponga gli invarianti tramite factory e servizi. Eserciti TypeScript Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare TypeScript Academy?

Non è richiesta alcuna esperienza precedente. TypeScript Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 3.

Quanto tempo richiede la lezione «Modellazione del dominio — aggregati, invarianti e servizi»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione TypeScript Academy?

Sì. Ogni lezione TypeScript Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Tipi brandizzati/opachi per evitare scambi tra unità
  2. ID con tag e pattern di modellazione del dominio
  3. Modellazione del dominio — aggregati, invarianti e servizi
← Torna a TypeScript Academy