skip to content

What is a `typealias` in Kotlin, and what does declaring `typealias Name = ExistingType` actually create?

level: juniorimportance: must knowfreq 55%

answer

  1. Synonym, not a new type
  2. Compiler expands to underlying type
  3. Zero runtime cost / no bytecode class
  4. Fully interchangeable, no cast
  5. Top-level (file) declaration

basics

~20 s

A typealias gives an existing type a second, shorter name. It does not make a new type — it is just an alias the compiler swaps back to the original. The two names are fully interchangeable.

solid answer

~40 s

`typealias Name = ExistingType` introduces a compile-time synonym for an existing type. It creates no new type, no class, and no runtime object: the compiler expands the alias to its underlying type during compilation, so there is zero runtime cost and nothing appears in the bytecode for the alias itself. Because it is the *same* type, `Name` and `ExistingType` are mutually assignable with no cast — you can pass one where the other is expected. Typealiases are declared at the top level of a file (or as a member), never inside a function body. Typical uses: shortening verbose generic types (`typealias Cache = Map<String, List<User>>`), naming function types for readability, or disambiguating an imported name. It is purely cosmetic and structural — there is no nominal distinction between the alias and the original.

code

kotlin · 10 lines
kotlin
typealias UserId = String

fun greet(id: UserId) = "Hi $id"

fun main() {
    val raw: String = "u-42"
    greet(raw)          // OK: UserId IS String, no cast
    val id: UserId = raw // OK: interchangeable both ways
    println(id.length)   // String members available directly
}

go deeper

for a junior

Knows it is a shorter name for an existing type and that there is no new type or cast.

for a middle

Explains compile-time expansion, zero runtime cost, and that it adds no type safety.

for a senior

Articulates structural vs nominal equivalence and contrasts with inline value class / wrapper class for real safety.

for a principal

Frames the trade-off (readability vs lost safety) and guides when an alias is appropriate vs a distinct domain type.

## What a `typealias` is A **type alias** is a *second name* for a type that already exists. You declare it with the `typealias` keyword: ```kotlin typealias UserId = String typealias UserCache = Map<UserId, List<User>> ``` Here `UserId` is **not** a new type — it is a **compile-time synonym** for `String`. The compiler **expands** (substitutes) the alias back to its underlying type wherever you use it, before generating bytecode. ## Key consequences - **No new type is created.** `UserId` and `String` are the *same* type to the compiler. They are **fully interchangeable** — assignable in both directions with no cast, no wrapper, no conversion. - **Zero runtime cost / zero runtime presence.** Nothing is emitted in the bytecode for the alias. At runtime there is no `UserId` class; everything is just `String`. (Contrast with an `inline value class`, which *is* a distinct type and can require boxing — that is a sibling topic.) - **No type safety added.** Because they are the same type, the compiler will *not* stop you from passing an `OrderId` where a `UserId` is expected if both alias `String`. - **Structural, not nominal.** Two aliases of the same underlying type are equivalent; the alias name is just sugar. ## Where you can declare it A `typealias` is a **top-level declaration** (file scope) or a member declaration. It **cannot** be declared inside a function body / local scope. ```kotlin typealias FileTable = MutableMap<String, MutableList<File>> fun newTable(): FileTable = mutableMapOf() // FileTable IS MutableMap<...> ``` ## Why use it - Shorten long generic types so signatures stay readable. - Give a domain-meaningful name to a type (`typealias Predicate = (Int) -> Boolean`). - Disambiguate a clashing imported name (`import ... as` is for *imports*; `typealias` is a real reusable name in the file/module). ## What it is NOT It is **not** a class, **not** a wrapper, **not** boxing, and adds **no** validation or distinct identity. If you need a genuinely distinct type, use a class or an `inline value class` instead.

  • Does a typealias add type safety, e.g. preventing a UserId from being used as an OrderId?
    No. If both alias String, they are the same type and freely interchangeable. For real distinction you need an inline value class or a wrapper class.
  • Can you declare a typealias inside a function body?
    No. typealias is a top-level or member declaration only; it is not allowed in local/statement scope.

Like a nickname: 'Bob' and 'Robert' point to the same person — calling either reaches the same individual, with no new person created.

saying these in an interview costs you the question

  • Saying typealias creates a new type or a subclass
  • Claiming it adds type safety or validation
  • Thinking it has runtime cost or boxes values
  • Saying you need a cast to convert alias <-> original
  • Confusing it with `import X as Y` (import-only renaming)

context