skip to content

What is a function-type typealias in Kotlin, and why would you declare something like `typealias Handler = (Event) -> Unit`?

level: juniorimportance: must knowfreq 55%

answer

  1. typealias = nickname for a type
  2. Same type, fully interchangeable
  3. Zero runtime cost, no wrapper class
  4. Top-level only
  5. Readability, not type safety

basics

~10 s

It gives a short, meaningful name to a function type. Instead of writing (Event) -> Unit everywhere, you write Handler. It is just an alias, so the two names mean exactly the same type.

solid answer

~40 s

A `typealias` introduces an alternative name for an existing type; for function types it makes higher-order signatures readable. `typealias Handler = (Event) -> Unit` lets you write `fun on(h: Handler)` instead of repeating `(Event) -> Unit`. It is purely a compile-time alias: `Handler` and `(Event) -> Unit` are the *same* type, fully assignment-compatible in both directions, with no wrapper, runtime cost, or new class. It does not create encapsulation or type-safety: any `(Event) -> Unit` lambda is a valid `Handler`. Typealiases must be declared at the top level (file scope), not inside a class or function. They are mainly a documentation/readability tool for parameters, return types, and complex generic function signatures.

code

kotlin · 11 lines
kotlin
typealias Handler = (Event) -> Unit

class Bus {
    private val handlers = mutableListOf<Handler>()
    fun on(h: Handler) { handlers += h }      // reads cleanly
    fun emit(e: Event) = handlers.forEach { it(e) }
}

// A plain lambda is a valid Handler — they are the same type:
val bus = Bus()
bus.on { event -> println("got $event") }

go deeper

for a junior

Knows typealias names a type and improves readability of callback parameters.

for a middle

Explains it is purely an alias — same type, interchangeable, no runtime cost, top-level only.

for a senior

Contrasts with fun interface / value class and articulates the no-type-safety tradeoff and when each is appropriate.

for a principal

Frames typealias as a documentation tool within an API design strategy, weighing readability vs. nominal typing across a module's public surface.

## What `typealias` does A **typealias** declares an alternative *name* for a type that already exists. The keyword is `typealias`. For a **function type** (a type describing a function value, written `(Params) -> ReturnType`), it lets you replace a hard-to-read inline type with a domain word. ```kotlin typealias Handler = (Event) -> Unit fun register(name: String, handler: Handler) { /* ... */ } // identical to: fun register(name: String, handler: (Event) -> Unit) { /* ... */ } ``` ## Key property: it is an *alias*, not a new type After `typealias Handler = (Event) -> Unit`, the names `Handler` and `(Event) -> Unit` are **fully interchangeable**. The compiler erases the alias before type checking, so: - A plain lambda `{ e: Event -> ... }` is a valid `Handler`. - A `Handler` value can be passed anywhere `(Event) -> Unit` is expected, and vice-versa. - There is **no wrapper class, no boxing, no runtime overhead** — `::class` / reflection see the underlying function type. This is the big difference from wrapping a function in a `class` or `value class`: an alias gives you readability but **zero** extra type safety. If you want a distinct, non-interchangeable type, you need a real class, not a typealias. ## Where you can declare it Typealiases must be **top-level** declarations (directly in a file). You cannot put one inside a class body or a function. They can be `private`/`internal` to limit visibility to a file/module. ## Why use it - **Readability** of higher-order signatures — `Validator<T>` reads better than `(T) -> Boolean`. - **Single point of change** — if the callback shape evolves, you update the alias once (callers using the alias still need to match the new shape, but the intent stays centralized). - **Self-documenting APIs** — names like `Reducer`, `Middleware`, `Comparator`-style aliases convey intent. ```kotlin typealias Validator<T> = (T) -> Boolean val notBlank: Validator<String> = { it.isNotBlank() } ``` ## What it is NOT - Not a new class or `interface` — use a `fun interface` if you need a named SAM type with its own identity. - Not encapsulation — it does not hide or restrict the underlying type.

  • Can you declare a typealias inside a class?
    No. Typealiases must be top-level declarations in a file; they cannot be nested in a class or function.
  • Does a typealias give you any extra type safety?
    No. It is just another name for the same type — any value of the underlying function type is accepted. For a distinct type use a class, value class, or fun interface.

Like a contact name in your phone: 'Mom' and the actual phone number are the same number, just one is easier to read.

saying these in an interview costs you the question

  • Claiming a typealias creates a new type or class
  • Thinking it adds type safety or prevents passing a raw lambda
  • Saying it has runtime overhead or boxes the function
  • Believing it can be declared inside a class or function body
  • Confusing it with a fun interface (SAM type)

context