
코틀린 sealed class는 enum보다 복잡해 보이지만, 실제로는 가능한 상태를 제한해서 실수를 줄이는 도구입니다. 특히 로딩, 성공, 실패처럼 서로 다른 데이터를 가진 상태를 표현할 때 차이가 큽니다.
핵심은 상태의 종류를 닫아 두고, 각 상태가 필요한 데이터를 타입으로 드러내는 것입니다. 이 글은 Kotlin 공식 sealed classes 문서를 기준으로 enum, data class, sealed class 선택 기준을 정리합니다.

코틀린 sealed class가 필요한 상황
sealed class는 가능한 하위 타입을 제한하고 싶을 때 사용합니다. 상태의 종류가 정해져 있고, 각 상태가 서로 다른 데이터를 가져야 한다면 sealed class가 enum보다 잘 맞습니다.
sealed class UiState {
data object Loading : UiState()
data class Success(val items: List<String>) : UiState()
data class Error(val message: String) : UiState()
}Loading은 추가 데이터가 필요 없고, Success는 목록이 필요하고, Error는 메시지가 필요합니다. 이런 차이를 하나의 타입 계층 안에서 안전하게 표현할 수 있습니다.
enum과 sealed class의 차이
enum은 고정된 상수 목록을 표현할 때 좋습니다. 예를 들어 요일, 정렬 방향, 단순 상태처럼 각 값이 같은 구조라면 enum이 더 단순합니다.
enum class SortDirection {
ASC,
DESC
}반면 각 상태마다 필요한 데이터가 다르면 enum만으로는 부족합니다. Error에는 원인 메시지가 필요하고, Success에는 실제 데이터가 필요할 수 있습니다.
when에서 빠진 상태를 줄일 수 있다
sealed class와 when을 함께 쓰면 가능한 하위 타입을 기준으로 분기할 수 있습니다. 모든 상태를 처리하면 else 없이 표현식으로 사용할 수 있어 빠진 상태를 줄이는 데 도움이 됩니다.
fun render(state: UiState): String = when (state) {
UiState.Loading -> "로딩 중"
is UiState.Success -> "${state.items.size}개"
is UiState.Error -> state.message
}나중에 `Empty` 같은 새 상태를 추가하면, 모든 분기 지점에서 그 상태를 처리해야 하는지 컴파일 단계에서 확인할 수 있습니다.
sealed interface는 언제 볼까
Kotlin에서는 sealed interface도 사용할 수 있습니다. 구현 타입을 제한하고 싶지만 class 상속 구조보다 역할 중심으로 묶고 싶을 때 선택지가 됩니다.
sealed interface PaymentResult
data object Pending : PaymentResult
data class Paid(val receiptId: String) : PaymentResult
data class Failed(val reason: String) : PaymentResultsealed class와 sealed interface 중 무엇이 항상 정답인 것은 아닙니다. 상태 계층이 객체의 기반 구현을 공유해야 하면 class가 자연스럽고, 타입 역할만 제한하면 interface도 검토할 수 있습니다.
data class 하나로 처리하면 왜 위험할까
상태를 하나의 data class에 nullable 필드 여러 개로 표현하면 불가능한 조합이 생길 수 있습니다. 예를 들어 loading인데 errorMessage도 있고 items도 있는 상태가 만들어질 수 있습니다.
data class BadUiState(
val loading: Boolean,
val items: List<String>?,
val errorMessage: String?
)sealed class는 불가능한 상태 조합을 타입 구조에서 줄이는 도구입니다. 화면 상태, 네트워크 결과, 결제 결과처럼 경우의 수가 닫혀 있을 때 특히 유용합니다.
실무 체크리스트
- 상태 종류가 닫혀 있는지 먼저 확인한다
- 각 상태가 서로 다른 데이터를 가지면 sealed class를 검토한다
- 단순 상수 목록이면 enum을 우선 검토한다
- when에서 모든 상태를 처리해야 하는 흐름이면 sealed가 유리하다
- nullable 필드 조합으로 불가능한 상태가 생기지 않는지 확인한다
정리
sealed class를 이해할 때는 문법을 짧게 쓰는 것보다, 코드가 표현해야 하는 의도를 먼저 보는 편이 좋습니다. 오늘 글의 기준은 ‘읽는 사람이 실수를 줄일 수 있는가’입니다.
함께 보면 좋은 내부 글은 코틀린 when은 switch와 무엇이 다를까: 조건문을 표현식으로 읽는 법, 코틀린 data class는 언제 쓰면 좋을까: equals와 copy가 자동으로 생기는 이유, Compose 상태 호이스팅은 언제 해야 할까: remember와 ViewModel 사이에서 상태 위치 정하기입니다. 외부 기준은 Kotlin Docs – Sealed classes and interfaces, Kotlin Docs – Control flow: when expressions and statements, Kotlin Docs – Enum classes를 확인했습니다.