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 ProductIdAggregato 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
- Tipi brandizzati/opachi per evitare scambi tra unità
- ID con tag e pattern di modellazione del dominio
- Modellazione del dominio — aggregati, invarianti e servizi