Modelowanie domeny — agregaty, niezmienniki i usługi
Modelowanie agregatów, takich jak Cart, za pomocą brandowanych identyfikatorów oraz wymuszanie niezmienników przez fabryki i usługi
Modelowanie domeny — agregaty, niezmienniki i usługi to bezpłatna lekcja TypeScript Academy na CoddyKit. To lekcja 3 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej TypeScript Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs TypeScript Academy zawiera 3 lekcji w sumie.
Wprowadzenie
Cel: Modelowanie agregatu Cart za pomocą brandowanych identyfikatorów i zapewnienie egzekwowania reguł, takich jak qty > 0, w fabrykach i usługach.
- Brandowane identyfikatory rozróżniają granice encji
- Fabryki zwracają unie Result
- Funkcje usługowe unikają nieprawidłowych przejść stanu
Encje i brandy
Brandowane identyfikatory sprawiają, że CartId i ProductId są niekompatybilne, mimo że oba mają typ string. Zapobiega to pomyłkom.
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 ProductIdAgregat i niezmiennik
Fabryki sprawdzają reguły: qty musi być większe niż > 0. Można utworzyć wyłącznie poprawne obiekty Line.
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) } }Usługa: dodawanie elementu
Funkcje usługowe wykonują bezpieczne przejścia i ponownie obliczają sumy. Jeśli sumy są nieprawidłowe, funkcja zwraca błąd zamiast uszkodzić stan.
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" }Mapowanie na granicach systemu
Na granicach systemu (np. w API) należy konwertować dane na DTO i weryfikować je podczas ponownego parsowania. Fabryki zapewniają poprawność danych.
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) } }
}Wskazówki
Najlepsze praktyki:
- Centralizować walidację w fabrykach.
- Utrzymywać funkcje usługowe jako czyste i deterministyczne.
- Wykonywać konwersje brandów wyłącznie na granicach systemu.
Sprawdzenie niezmiennika
Szybkie sprawdzenie: Jak należy egzekwować niezmiennik taki jak qty > 0?
Podsumowanie
Podsumowanie: Brandowane identyfikatory w połączeniu z fabrykami i usługami egzekwują niezmienniki. Nieprawidłowe stany nie mogą zostać utworzone, ponieważ wszystkie punkty wejścia weryfikują dane.
Często zadawane pytania
Czy lekcja „Modelowanie domeny — agregaty, niezmienniki i usługi” jest bezpłatna?
Tak — pełny tekst „Modelowanie domeny — agregaty, niezmienniki i usługi” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu TypeScript Academy, przejdź na CoddyKit PRO. Kurs TypeScript Academy zawiera 3 lekcji w sumie.
Co nauczysz się w „Modelowanie domeny — agregaty, niezmienniki i usługi”?
Modelowanie agregatów, takich jak Cart, za pomocą brandowanych identyfikatorów oraz wymuszanie niezmienników przez fabryki i usługi Ćwiczysz TypeScript Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć TypeScript Academy?
Nie wymagamy żadnego doświadczenia. TypeScript Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 3.
Ile czasu zajmuje lekcja „Modelowanie domeny — agregaty, niezmienniki i usługi”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji TypeScript Academy?
Tak. Każda lekcja TypeScript Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Typy branding/opaque zapobiegające pomyłkom jednostek
- Identyfikatory tagowane i wzorce modelowania domeny
- Modelowanie domeny — agregaty, niezmienniki i usługi