Sealed Interfaces

A sealed interface works the same way, but a class can implement several sealed interfaces, and enums or data objects can implement them too. Many teams prefer sealed interfaces for state because they have no constructor to call.

Example

sealed interface Event
sealed interface Trackable { val eventName: String }

data class Click(val button: String) : Event, Trackable {
    override val eventName = "click_$button"
}
data class Scroll(val percent: Int) : Event
data object AppOpened : Event, Trackable {
    override val eventName = "app_open"
}

fun handle(e: Event) = when (e) {
    is Click -> "User tapped ${e.button}"
    is Scroll -> "Scrolled to ${e.percent}%"
    AppOpened -> "App opened"
}

fun main() {
    val events = listOf(AppOpened, Click("buy"), Scroll(70))
    events.forEach { println(handle(it)) }
    println(events.filterIsInstance<Trackable>().map { it.eventName })
}

Output

App opened
User tapped buy
Scrolled to 70%
[app_open, click_buy]