Typealias — その概要、構文、Kotlinでの使用法

著者: IT Sectr 公開日: 2026-06-23 読了時間: 7 分

Typealiasは、既存の型に別名を作成するためのKotlinのメカニズムです。typealiasキーワードを使用すると、新しい型を作成せずに、複雑な型宣言を短く明確なエイリアスに置き換えることができます。Kotlinドキュメント(2026)によると、typealiasは特に関数型を持つ関数シグネチャにおいて、コードの可読性を向上させます。Typealiasは、冗長な宣言を明確な名前付き型に置き換えることで、コードを自己文書化します。

重要なポイント

  • Typealias — 新しい型を作成しない、既存の型のエイリアス
  • 関数型 — typealiasは複雑な(T)-> RをCallbackのような読みやすい名前に置き換えます
  • ジェネリクス — typealiasはジェネリックパラメータをサポート:typealias ListMapper = (T) -> T
  • ネストされたクラス — typealiasは他のパッケージからのネストされたクラスへのアクセスを短縮します
  • 型安全性 — typealiasはコンパイル時のチェックを追加しません。エイリアスは元の型と完全に交換可能です

Typealiasとは?

Typealias(型エイリアス)は、既存の型に代替名を導入する宣言です。構文:typealias 新しい名前 = 既存の型。宣言後、新しい名前は既存の型が期待される場所で使用でき、コンパイラはそれらを同じ型として扱います。バイトコードレベルでは、typealiasは痕跡を残しません。すべてのエイリアス情報はコンパイル時に消去されます。

Typealiasの主な目的はコードの可読性を向上させることです。冗長なシグネチャ fun process(callback: (Result) -> Unit) の代わりに、typealias Callback = (Result) -> Unit と記述してCallbackをパラメータ型として使用できます。これは、同じ関数型がコード内の複数の場所で繰り返される場合に特に便利です。エイリアスは定義の単一ポイントとして機能し、型の目的を文書化します。

Typealiasは新しい型を作成しません — 単なる同義語です。Callback型と(Result) -> Unit型の変数は完全に交換可能です。Callbackを期待する関数にラムダを直接渡しても、コンパイラはエラーを生成しません。これにより、typealiasはコンパイル時チェックを行う新しいラッパー型を作成するinline class(value class)とは区別されます。Typealiasは名前の変更であり、ラップではありません。

関数型のTypealias

Kotlinでのtypealiasの最も一般的な使用例は関数型です。(Int, String) -> Boolean や (List) -> Result のような長いシグネチャはコードを読みにくくします。Typealiasはそれらを関数の目的を文書化する短い意味のある名前に変換します:typealias Validator = (String) -> Boolean はこれが文字列バリデータであることを指定します。

kotlin
// Without typealias
fun findUsers(
    filter: (List<User>) -> List<User>
): List<User>

// With typealias
typealias UserFilter = (List<User>) -> List<User>

fun findUsers(filter: UserFilter): List<User>

// Usage in class
typealias OnClickListener = (View) -> Unit

class Button {
    var onClick: OnClickListener = {}
}

この例では、typealias UserFilter が複雑な関数型 (List) -> List を短い名前の背後に隠しています。findUsersのシグネチャは「UserFilterを受け取り、Listを返す」と読みやすくなります。typealias OnClickListener は、別のインターフェースや抽象クラスを作成するオーバーヘッドなしで、コードをインターフェース宣言のように見せます。一方、ラムダや無名関数は通常通り動作し続けます — typealiasは呼び出し側のコードに変更を必要としません。

ジェネリクスを使用したTypealias

Typealiasはジェネリックパラメータをサポートしており、さらに柔軟性が高まります。typealias Mapper = (T) -> R を定義して、任意の型で使用できます。コンパイラはエイリアスを使用するたびにパラメータを特定の型で置き換え、完全な型安全性を維持します。

kotlin
// Generic typealias
typealias Mapper<T, R> = (T) -> R
typealias Provider<T> = () -> T
typealias ListTransformer<T> = (List<T>) -> List<T>

fun processNumbers(mapper: Mapper<Int, String>) {
    // mapper type is (Int) -> String
}

fun main() {
    val config: Provider<String> = { "default config" }
    val reverse: ListTransformer<Int> = { it.reversed() }
}

リストでは、Mapper はTからRへの任意の変換のためのジェネリックエイリアスです。Providerは値のサプライヤー(引数のないファクトリ)です。ListTransformerはリスト変換関数です。processNumbers(mapper: Mapper) を呼び出すと、コンパイラはエイリアスを (Int) -> String に展開します。ジェネリクスにより、typealiasは宣言を複製することなく任意のコンテキストに適した汎用ツールになります。

ネストされた長い名前のTypealias

ネストされたクラスと長いパラメータ化された型は、typealiasがコードを大幅に簡素化するもう1つの領域です。クラスがネスト階層(Outer.Inner.Nested)の深いところにある場合、完全な名前で参照するとコードが乱雑になります。Typealiasはそのようなアクセスを短縮し、より読みやすくします。これは特に、長い名前を持つサードパーティライブラリのクラスに関連します。

kotlin
// Alias for nested class
class NetworkResponse {
    class Error(val code: Int, val message: String)
}
typealias NetworkError = NetworkResponse.Error

// Alias for long library type
typealias UserId = Long
typealias JsonMap = Map<String, Any?>

fun process(error: NetworkError) {
    println("${error.code}: ${error.message}")
}

fun parseJson(data: JsonMap): UserId {
    return data["id"] as? Long ?: 0L
}

この例では、NetworkError はネストされたクラス NetworkResponse.Error のエイリアスです。typealiasをインポートすることで、ネスト階層を明らかにせずにNetworkErrorを通常の型として使用できます。JsonMap はマップがJSONオブジェクトを表すことを文書化します。UserId は特定のコンテキストでのLongの目的を明確にし、読者はそれが任意の数値ではなくユーザー識別子であることをすぐに理解できます。ただし、typealiasはUserIdが期待される場所にプレーンなLongを渡すことを防ぎません — そのためにはvalue classが必要です。

Typealias vs Inline Class:違い

Typealiasinline class(value class)は、どちらも型に新しい名前を導入しますが、異なる問題を解決します。Typealiasは単なる同義語です:UserId = Long 型の変数はチェックなしで任意のLongを受け入れます。Inline classは値をコンパイル時にチェックされる新しい型にラップします。inline class UserIdが期待される場所に、明示的な変換なしでプレーンなLongを渡すことはできません。

特徴TypealiasInline class
新しい型いいえ — 元の型の同義語はい — チェック付きの新しい型
パフォーマンスゼロ — 完全に消去されるゼロ — バイトコードでラッパーが削除される
継承いいえいいえ(最終クラス)
独自のメソッドいいえはい — 関数を宣言可能
型安全性いいえ — 元の型と交換可能はい — コンパイラが型を区別する

表は2つのメカニズムの違いを示しています。Typealiasは、厳密な型付けが不要な場合の簡潔な名前とコード文書化に適しています。value classキーワード(以前はinline class)によるInline classは、同じプリミティブ型の意味的に異なる値を区別することが重要な場合に必要です。たとえば、UserIdとOrderIdはどちらもLongですが、一方が期待される場所に他方を渡すことは論理エラーであり、value classがコンパイル時に防止します。

よくある質問

Typealiasはimport aliasとどう違うのですか?

Import alias(import com.example.LongName as Short)はインポートレベルで機能し、現在のファイル内でのみ名前を短縮します。Typealiasはインポート後、プロジェクト全体で利用可能なグローバルエイリアスを宣言します。

再帰的な型を作成するためにtypealiasを使用できますか?

はい、typealiasは関数型の再帰的定義をサポートしていますが、注意が必要です:typealias Rec = (T) -> Rec は機能しますが、objectへの再帰的参照は機能しません。コンパイラは循環をチェックし、無限の定義に対してエラーを生成します。

Typealiasはパフォーマンスに影響しますか?

いいえ、typealiasはコンパイル時に完全に消去されます。バイトコードとランタイムレベルでは、ラッパーなしで元の型が使用されます。パフォーマンスは元の型を直接使用するのと同じです。

Typealiasの最大ネストレベルはいくつですか?

Typealiasは別のtypealiasを参照できます — これはエイリアスのチェーンと呼ばれます。チェーンの深さは正式には無制限ですが、可読性のために2〜3レベル以下が推奨されます。コンパイラは分析段階でチェーンを完全に解決します。

関数内でtypealiasを宣言できますか?

いいえ、typealiasはトップレベル宣言またはクラス/オブジェクトのメンバーです。関数内でtypealiasを宣言することはできません。ローカルな型の短縮には、ファイル内でimport aliasを使用するか、typealiasをモジュールレベルに配置してください。

まとめ

  • Typealias — 新しい型を作成せず、コンパイル時に消去される既存の型の同義語
  • 関数型 — 主な使用例:typealiasは(T)-> RをCallbackのような読みやすい名前に置き換える
  • ジェネリクス typealiasでは任意の型に対してジェネリックエイリアスMapperを作成可能
  • ネストされたクラス — typealiasは深くネストされた型やライブラリの長い名前へのアクセスを短縮する
  • 型安全性はなし:typealiasは元の型と完全に交換可能
  • Value class — 実行時コストゼロで厳密な型チェックが必要な場合のtypealiasの代替
  • 可読性 — 主な利点:意味のある型名がオーバーヘッドなしでコードを自己文書化する

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください