kotlinbeginner

Type Aliases for Readable Code

Simplify complex types with typealias: function types, generic types, and callback signatures.

kotlin
// Function type aliases
typealias Handler<T> = (T) -> Unit
typealias AsyncCallback<T> = (Result<T>) -> Unit
typealias Predicate<T> = (T) -> Boolean
typealias Mapper<T, R> = (T) -> R
typealias BiFunction<A, B, R> = (A, B) -> R

// Generic type aliases
typealias StringMap<V> = Map<String, V>
typealias MutableStringMap<V> = MutableMap<String, V>
typealias Matrix<T> = List<List<T>>
typealias JSON = Map<String, Any?>

// Domain aliases
typealias UserId = Long
typealias Email = String
typealias Score = Double
typealias Timestamp = Long

// Complex generic aliases
typealias ResultHandler<T> = (Result<T>) -> Unit
typealias Middleware<T> = (T, Handler<T>) -> Unit
typealias ValidationRule<T> = (T) -> String?
typealias EventListener<E> = suspend (E) -> Unit

// Using aliases in APIs
class EventEmitter<E> {
    private val listeners = mutableListOf<Handler<E>>()

    fun on(listener: Handler<E>) { listeners.add(listener) }
    fun emit(event: E) { listeners.forEach { it(event) } }
}

class Validator<T>(private val rules: List<ValidationRule<T>>) {
    fun validate(value: T): List<String> = rules.mapNotNull { it(value) }
}

fun fetchUser(id: UserId, callback: AsyncCallback<String>) {
    try {
        val result = "User-$id"
        callback(Result.success(result))
    } catch (e: Exception) {
        callback(Result.failure(e))
    }
}

// Chain middleware
class Pipeline<T> {
    private val middlewares = mutableListOf<Middleware<T>>()

    fun use(mw: Middleware<T>) { middlewares.add(mw) }

    fun execute(value: T) {
        fun runNext(index: Int, v: T) {
            if (index < middlewares.size) {
                middlewares[index](v) { next -> runNext(index + 1, next) }
            }
        }
        runNext(0, value)
    }
}

fun main() {
    // Function aliases
    val isPositive: Predicate<Int> = { it > 0 }
    val double: Mapper<Int, Int> = { it * 2 }
    val add: BiFunction<Int, Int, Int> = { a, b -> a + b }

    println(isPositive(5))     // true
    println(double(21))        // 42
    println(add(10, 20))       // 30

    // Generic aliases
    val config: StringMap<Any> = mapOf("host" to "localhost", "port" to 8080)
    println("Config: $config")

    val matrix: Matrix<Int> = listOf(listOf(1, 2), listOf(3, 4))
    println("Matrix: $matrix")

    // Domain aliases
    val userId: UserId = 42L
    val email: Email = "alice@test.com"
    fetchUser(userId) { result ->
        result.fold(
            onSuccess = { println("User: $it") },
            onFailure = { println("Error: ${it.message}") }
        )
    }

    // Validator
    val emailValidator = Validator<String>(listOf(
        { if (it.isBlank()) "Email required" else null },
        { if (!it.contains("@")) "Invalid email" else null },
        { if (it.length > 255) "Email too long" else null }
    ))
    println("Validate: ${emailValidator.validate("test")}")
    println("Validate: ${emailValidator.validate("test@example.com")}")

    // Pipeline
    val pipeline = Pipeline<String>()
    pipeline.use { value, next -> println("Step 1: $value"); next(value.uppercase()) }
    pipeline.use { value, next -> println("Step 2: $value"); next("[$value]") }
    pipeline.use { value, _ -> println("Final: $value") }
    pipeline.execute("hello")
}

Use Cases

  • Simplifying complex function signatures
  • Domain-specific type naming
  • Readable callback and handler definitions

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.