Skip to content

Sport discrimination

SportEvent and Market are discriminated unions. The SDK’s TypeScript types let you narrow on a discriminator and access fields that only exist on the matching variant — without casts.

SportEvent is the union BasketballMatch | FootballMatch | TennisMatch. The discriminator is sport:

client.on('sportEvent:added', ({ sportEvent }) => {
if (sportEvent.sport === 'basketball') {
sportEvent.homeTeam // typed as string
sportEvent.awayTeam // typed as string
} else if (sportEvent.sport === 'tennis') {
sportEvent.competitor1 // typed as string
sportEvent.competitor2 // typed as string
} else if (sportEvent.sport === 'football') {
sportEvent.homeTeam // typed as string
}
})

You can also narrow on kind, which is the underlying string discriminator ('se:basketball_match', etc.). sport is a computed convenience derived from kind — they always agree.

Market is a six-way union. Narrowing on kind reveals the variant fields:

for (const market of sportEvent.markets.values()) {
if (market.kind === 'market:basketball_match.handicap') {
market.handicap // number, only on the handicap variant
market.period // BasketballPeriod
} else if (market.kind === 'market:basketball_match.total') {
market.cut // total points threshold
market.scope // 'match' | 'home' | 'away'
} else if (market.kind === 'market:basketball_match.player_prop_over_under') {
market.playerName // string
market.propType // 'points' | 'rebounds' | …
market.cut // threshold
}
}

The full list of MarketKind values is in Markets.

Selection.kind mirrors the parent market’s selectionKind. Selection.result is the specific outcome:

for (const selection of market.selections.values()) {
// selection.kind: 'over/under' | 'home/draw/away' | 'home/away' | 'competitor1/competitor2'
// selection.result: 'over' | 'under' | 'home' | 'draw' | 'away' | 'competitor1' | 'competitor2'
}

result is constrained by kind — TypeScript will reject impossible combinations (e.g. result: 'draw' when kind: 'home/away').

Switch with satisfies for exhaustive coverage

Section titled “Switch with satisfies for exhaustive coverage”
function describe(market: Market): string {
switch (market.kind) {
case 'market:basketball_match.moneyline': return 'basketball ML'
case 'market:basketball_match.handicap': return `basketball spread (${market.handicap})`
case 'market:basketball_match.total': return `basketball total ${market.cut}`
case 'market:basketball_match.player_prop_over_under':
return `${market.playerName} ${market.propType} O/U ${market.cut}`
case 'market:football_match.moneyline': return 'football 1X2'
case 'market:tennis_match.moneyline': return 'tennis ML'
}
market satisfies never // TypeScript error if a kind is added without updating this switch
}

The market satisfies never pattern catches missing branches at compile time the next time a new market kind is introduced.