By David Winer, Product Manager, Kotlin

Sometimes type declarations that are not readable, explicit, or have long names interfere with the code’s “self-expression.” In this case, you can use a feature Kotlin provides specifically for this problem: Typealias (” Typealias “in this article). Type aliases allow you to provide alternative names for existing class or function types without adding new types.

The use of type aliases

Use type aliases to name function types:

typealias TeardownLogic = () -> Unit
fun onCancel(teardown : TeardownLogic){ }
private typealias OnDoggoClick = (dog: Pet.GoodDoggo) -> Unit
val onClick: OnDoggoClick
Copy the code

Note, however, that this use hides the incoming arguments and makes them less readable:

typealias TeardownLogic = () -> Unit typealias TeardownLogic = (exception: Exception) -> Unit fun onCancel(teardown : TeardownLogic){// It is not easy to know what to expect from TeardownLogic}Copy the code

Type aliases help shorten long generic class names:

typealias Doggos = List<Pet.GoodDoggo>
fun train(dogs: Doggos){ ... }
Copy the code

When using type aliases, you need to think about whether this is necessary: Does using type aliases here really make your code more meaningful and readable?

Think about whether using type aliases makes your code easier to understand

If you are using a long class name, you can shorten it by using a type alias:

typealias AVD = AnimatedVectorDrawable
Copy the code

In this example, it would be more appropriate to use an import alias:

import android.graphics.drawable.AnimatedVectorDrawable as AVD
Copy the code

A more applicable scenario is if the same class name from a different package appears in your code, you can use an import alias to disambiguate such an occurrence:

import io.plaidapp.R as appR
import io.plaidapp.about.R
Copy the code

Because type aliases need to be declared outside the class, you need to consider restricting their visibility when using them.

Use type aliases in multi-platform projects

When developing multi-platform projects with Kotlin, you can write an interface in common Code and implement it in the appropriate platform code. Kotlin provides mechanisms for “actual declarations” and “expected declarations” to simplify this. Interfaces declared in common code are expected declarations, using the Expect keyword; The extension in the corresponding platform code is the actual declaration, using the actual keyword. If an interface in common code is already implemented in platform code, and all expected methods are signed identically, you can map the actual declared type name to the expected type using the type alias:

expect annotation class Test
actual typealias Test = org.junit.Test
Copy the code

The working principle of

Type aliases do not introduce new types. For example, after decompiling the train and play methods, you can see that the arguments passed in use only the List type:

// Kotlin typealias Doggos = List<Pet.GoodDoggo> fun train(dogs: Doggos) { ... } fun play(dogs: Doggos) { ... Public static final void train(@notnull List dogs) {public static final void train(@notnull List dogs) { } public static final void play(@notnull List dogs) {... }Copy the code

Type aliases do not introduce new types

Therefore, you should not rely on type aliases for compilation type checking, but instead use a different type or inline class. For example, in the following method, we need to pass a long integer argument:

fun play(dogId: Long)
Copy the code

Giving an alias for a long integer does not prevent you from passing in the wrong ID:

Typealias DogId = Long Fun pet(DogId: DogId) {... typeAlias DogId = Long Fun pet(DogId: DogId) {... } funusage() {
    val cat = Cat(1L)
    pet(cat.catId) // compiles
}
Copy the code

A type alias provides a shorter or more meaningful name for an existing type. But if you’re looking for more security, creating a new type makes sense.