TypeScript Academy · Lektion

Domänmodellering – aggregat, invarianta villkor och tjänster

Modellera aggregat som Cart med brandade ID:n och upprätthåll invarianta villkor via fabriker och tjänster.

Lektion 3 av 38 steg

Domänmodellering – aggregat, invarianta villkor och tjänster är en gratis lektion i TypeScript Academy på CoddyKit. Detta är lektion 3 av 3. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för TypeScript Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i TypeScript Academy innehåller totalt 3 lektioner.

Introduktion

Mål: Modellera ett Cart-aggregat med brandade ID:n och säkerställ att regler som qty > 0 upprätthålls i fabriker och tjänster.

  • Brandade ID:n skiljer entitetsgränser åt
  • Fabriker returnerar Result-unioner
  • Tjänstefunktioner undviker ogiltiga övergångar

Entiteter och brandning

Brandade ID:n gör CartId och ProductId inkompatibla trots att båda är strängar. Det förhindrar sammanblandningar.

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

Aggregat och invariant

Fabriker validerar regler: qty måste vara > 0. Endast giltiga Line-objekt kan skapas.

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

Tjänst: lägg till artikel

Tjänstefunktioner utför säkra övergångar och räknar om summor. Om summorna är ogiltiga returnerar funktionen ett fel i stället för att förstöra tillståndet.

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

Mappning vid gränser

Vid gränser, till exempel API:er, konverterar du till DTO:er och validerar när data läses tillbaka. Fabriker säkerställer att data är korrekt.

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

Tips

Bästa praxis:

  • Centralisera valideringen i fabriker.
  • Håll tjänstefunktioner rena och deterministiska.
  • Gör brandningskonverteringar endast vid systemgränser.

Kontroll av invarians

Snabb kontroll: Hur bör du upprätthålla en invariant som qty > 0?

Sammanfattning

Sammanfattning: Brandade ID:n tillsammans med fabriker och tjänster upprätthåller invariants. Ogiltiga tillstånd kan inte skapas eftersom alla ingångspunkter validerar indata.

Gratis att börja

Lär dig TypeScript med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
101
Lektioner
352

Vanliga frågor

Är lektionen ”Domänmodellering – aggregat, invarianta villkor och tjänster” gratis?

Ja – hela texten till ”Domänmodellering – aggregat, invarianta villkor och tjänster” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i TypeScript Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i TypeScript Academy innehåller totalt 3 lektioner.

Vad lär jag mig i ”Domänmodellering – aggregat, invarianta villkor och tjänster”?

Modellera aggregat som Cart med brandade ID:n och upprätthåll invarianta villkor via fabriker och tjänster. Ni övar på TypeScript Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig TypeScript Academy?

Du behöver inga förkunskaper. Utbildningen i TypeScript Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 3.

Hur lång tid tar lektionen ”Domänmodellering – aggregat, invarianta villkor och tjänster”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här TypeScript Academy-lektionen?

Ja. Varje TypeScript Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Branding-/opaque-typer för att förhindra sammanblandning av enheter
  2. Taggade ID:n och mönster för domänmodellering
  3. Domänmodellering – aggregat, invarianta villkor och tjänster
← Tillbaka till TypeScript Academy