코틀린 언어 용어 사전
클래스sealed interface · enum · 상태 모델링

sealed class

하위 타입이 컴파일 시점에 고정된 계층. when에서 else 없이 망라 검사가 가능해진다.

하위 타입의 종류가 컴파일 시점에 고정된 클래스 계층.

sealed interface UiState {
    data object Loading : UiState
    data class Success(val items: List<Item>) : UiState
    data class Error(val message: String) : UiState
}

무엇을 얻나 — 망라 검사

when (state) {
    is UiState.Loading -> showSpinner()
    is UiState.Success -> showItems(state.items)   // 스마트 캐스트로 items 에 바로 접근
    is UiState.Error -> showError(state.message)
    // else 가 필요 없다 — 컴파일러가 전부임을 안다
}

새 하위 타입을 추가하면 모든 when이 컴파일 에러로 알려 준다. 처리를 빠뜨릴 수 없다.

else 를 쓰면 이 이점이 사라진다

  • 새 타입이 추가돼도 조용히 else 로 흘러간다
  • sealed 를 쓰는 의미가 없어진다

enum과 무엇이 다른가

enum class Status { LOADING, SUCCESS, ERROR }   // 각 값이 '인스턴스 하나'

sealed interface UiState { ... }                 // 각 하위 타입이 '자기 데이터' 를 갖는다
  • enum — 상태의 종류만 필요하다. 값마다 데이터가 다르지 않다

  • sealed — 상태마다 다른 데이터를 들고 다녀야 한다

  • "성공이면 목록, 실패면 메시지" 처럼 데이터가 갈리면 sealed 다

왜 강력한가 — 불가능한 상태를 없앤다

// ❌ 플래그로 표현하면 말이 안 되는 조합이 만들어진다
data class State(
    val isLoading: Boolean,
    val items: List<Item>?,
    val error: String?
)
// isLoading=true 인데 error 도 있는 상태가 표현 가능하다 — 실제로는 불가능한데

// ✅ sealed 로는 애초에 만들 수 없다

"불가능한 상태를 표현 불가능하게 만든다" 가 이 설계의 핵심 가치다.

제약과 최신 문법

하위 타입은 같은 패키지·같은 모듈 안에 있어야 한다 (Kotlin 1.5+)

  • 라이브러리 사용자가 임의로 확장할 수 없다

sealed interface 가 sealed class 보다 유연하다

  • 다중 상속이 가능하고, 상태를 여러 계층으로 분류할 수 있다

data object (Kotlin 1.9+)

  • object 에도 toString·equals 가 자동 생성된다

면접 함정

  • "sealed는 상속을 막는다" → 같은 모듈 안에서는 상속할 수 있다. 에서 못 할 뿐이다.
  • "when에 else를 넣으면 안전하다" → 오히려 망라 검사를 잃는다.

Result 타입을 직접 만든다

sealed interface Result<out T> {
    data class Success<T>(val data: T) : Result<T>
    data class Failure(val error: Throwable) : Result<Nothing>
}

fun <T> Result<T>.getOrNull(): T? = when (this) {
    is Result.Success -> data
    is Result.Failure -> null
}

out T 와 Nothing 의 조합이 핵심이다

  • Nothing 은 모든 타입의 하위 타입이라
  • Failure 하나로 Result<무엇이든> 자리에 들어갈 수 있다

상태를 계층으로 나누기

sealed interface UiState
sealed interface Loadable : UiState        // 여러 계층으로 분류할 수 있다 (interface 라서)
data object Loading : Loadable
data class Success(val items: List<Item>) : Loadable
data class Error(val msg: String) : UiState

코틀린 표준 Result와의 차이

kotlin.Result 는 value class 라 제약이 있다

  • 반환 타입으로만 쓸 수 있었다 (지금은 완화됐지만)
  • 실패 타입을 Throwable 로 고정한다

도메인 오류를 타입으로 표현하고 싶으면 직접 sealed 로 만드는 편이 낫다

  • sealed interface LoginError { data object WrongPassword; data object Locked ... }

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 클래스·객체 — data·sealed·enum·object·생성자