Domain Modeling With Types


TypeScript is not the best for this due to its type system being structural. But here an example:

Typescript
type Suit = 'club' | 'diamond' | 'spade' | 'heart'
type Rank = 'two' | 'three' | 'four' | 'five' | 'six' | 'seven' | 'eight' | 'nine' | 'ten' | 'jack' | 'queen' | 'king' | 'ace'
type Card = {
    suit: Suit,
    rank: Rank
}
type Hand = Card[]
type Deck = Card[]
type ShuffledDeck = Card[]

type Player = { name: string, hand: Hand }
type Game = { deck: Deck, players: Player[] }

type Deal = (deck: ShuffledDeck) => [ShuffledDeck, Card]
type Shuffle = (deck: Deck) => ShuffledDeck
type PickupCard = (hand: Hand, card: Card) => Hand

// Example implementation/usage
const shuffle: Shuffle = (deck) => {
    return deck.sort(() => Math.random() - 0.5)
}
const dealCard: Deal = (shuffledDeck) => {
    return [shuffledDeck.slice(1), shuffledDeck[0]]
}

const myDeck: Deck = [{rank: "seven", suit: "spade"}, {rank: "ace", suit: "heart"}]
const myShuffledDeck: ShuffledDeck = shuffle(myDeck)
const [newDeck, card] = dealCard(myShuffledDeck)

console.log(newDeck) // [{"rank": "ace", "suit": "heart"}]
console.log(card) // {"rank": "seven", "suit": "spade"}]