Typealias — nó là gì, cú pháp và cách sử dụng trong Kotlin

Tác giả: IT Sectr Đã đăng: 2026-06-23 Thời gian đọc: 7 phút

Typealias là một cơ chế Kotlin để tạo tên thay thế cho một kiểu hiện có. Từ khóa typealias cho phép bạn thay thế một khai báo kiểu phức tạp bằng một bí danh ngắn và rõ ràng mà không tạo ra kiểu mới. Theo tài liệu Kotlin (2026), typealias cải thiện khả năng đọc mã, đặc biệt trong chữ ký hàm với các kiểu hàm. Typealias làm cho mã tự động được tài liệu hóa bằng cách thay thế các khai báo dài dòng bằng các kiểu được đặt tên rõ ràng.

Những điểm chính

  • Typealias — bí danh cho một kiểu hiện có, không tạo ra kiểu mới
  • Kiểu hàm — typealias thay thế (T) -> R phức tạp bằng các tên dễ đọc như Callback
  • Generic — typealias hỗ trợ tham số tổng quát: typealias ListMapper = (T) -> T
  • Lớp lồng nhau — typealias rút ngắn truy cập vào các lớp lồng nhau từ các gói khác
  • An toàn kiểu — typealias không thêm kiểm tra lúc biên dịch; bí danh có thể thay thế hoàn toàn cho bản gốc

Typealias là gì?

Typealias (bí danh kiểu) là một khai báo giới thiệu một tên thay thế cho một kiểu hiện có. Cú pháp: typealias TênMới = KiểuHiệnTại. Sau khi khai báo, TênMới có thể được sử dụng ở bất cứ đâu mà KiểuHiệnTại được mong đợi — trình biên dịch coi chúng là cùng một kiểu. Ở cấp độ bytecode, typealias không để lại dấu vết: tất cả thông tin bí danh đều bị xóa trong quá trình biên dịch.

Mục đích chính của typealias là cải thiện khả năng đọc mã. Thay vì một chữ ký dài dòng fun process(callback: (Result) -> Unit), bạn có thể viết typealias Callback = (Result) -> Unit và sử dụng Callback làm kiểu tham số. Điều này đặc biệt hữu ích khi cùng một kiểu hàm được lặp lại ở nhiều nơi trong mã: bí danh đóng vai trò là một điểm định nghĩa duy nhất và ghi lại mục đích của kiểu.

Typealias không tạo ra kiểu mới — nó chỉ là một từ đồng nghĩa. Các biến kiểu Callback và (Result) -> Unit có thể thay thế hoàn toàn cho nhau. Trình biên dịch sẽ không báo lỗi nếu một lambda được truyền trực tiếp vào một hàm mong đợi Callback. Điều này phân biệt typealias với inline class (value class), tạo ra một kiểu bao bọc mới với kiểm tra lúc biên dịch. Typealias là đổi tên, không phải bao bọc.

Typealias cho kiểu hàm

Trường hợp sử dụng phổ biến nhất của typealias trong Kotlin là các kiểu hàm. Các chữ ký dài như (Int, String) -> Boolean hoặc (List) -> Result làm cho mã khó đọc. Typealias biến chúng thành các tên ngắn có ý nghĩa ghi lại mục đích của hàm: typealias Validator = (String) -> Boolean chỉ rõ đây là trình xác thực chuỗi.

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 = {}
}

Trong ví dụ, typealias UserFilter ẩn kiểu hàm phức tạp (List) -> List đằng sau một tên ngắn. Chữ ký của findUsers trở nên dễ đọc: “chấp nhận UserFilter, trả về List”. Typealias OnClickListener làm cho mã giống như một khai báo giao diện nhưng không có chi phí tạo ra một giao diện hoặc lớp trừu tượng riêng. Trong khi đó, các lambda và hàm ẩn danh tiếp tục hoạt động bình thường — typealias không yêu cầu thay đổi trong mã gọi.

Typealias với Generic

Typealias hỗ trợ tham số tổng quát (generic), khiến nó càng linh hoạt hơn. Bạn có thể định nghĩa typealias Mapper = (T) -> R và sử dụng với bất kỳ kiểu nào. Trình biên dịch thay thế các kiểu cụ thể cho các tham số ở mỗi lần sử dụng bí danh, bảo toàn an toàn kiểu đầy đủ.

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() }
}

Trong danh sách, Mapper là một bí danh tổng quát cho bất kỳ sự chuyển đổi nào từ T sang R. Provider là một nhà cung cấp giá trị (một nhà máy không đối số). ListTransformer là một hàm chuyển đổi danh sách. Khi gọi processNumbers(mapper: Mapper), trình biên dịch mở rộng bí danh thành (Int) -> String. Generic làm cho typealias trở thành một công cụ phổ quát phù hợp cho mọi ngữ cảnh mà không cần nhân đôi khai báo.

Typealias cho tên lồng nhau và dài

Các lớp lồng nhau và các kiểu được tham số hóa dài là một lĩnh vực khác mà typealias đơn giản hóa đáng kể mã. Nếu một lớp nằm sâu trong hệ phân cấp lồng nhau (Outer.Inner.Nested), việc tham chiếu nó bằng tên đầy đủ sẽ làm mã trở nên lộn xộn. Typealias rút ngắn truy cập đó và làm cho nó dễ đọc hơn. Điều này đặc biệt phù hợp cho các lớp từ thư viện bên thứ ba với tên dài.

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
}

Trong ví dụ, NetworkError là một bí danh cho lớp lồng nhau NetworkResponse.Error. Bằng cách nhập typealias, bạn có thể sử dụng NetworkError như một kiểu thông thường mà không cần tiết lộ hệ phân cấp lồng nhau. JsonMap ghi lại rằng bản đồ đại diện cho một đối tượng JSON. UserId làm rõ mục đích của Long trong một ngữ cảnh cụ thể — người đọc hiểu ngay rằng đây là một định danh người dùng, không phải một số tùy ý. Tuy nhiên, typealias không ngăn việc truyền một Long đơn giản vào nơi UserId được mong đợi — để làm điều đó, cần có value class.

Typealias vs Inline Class: khác biệt

Typealiasinline class (value class) giải quyết các vấn đề khác nhau, mặc dù cả hai đều giới thiệu một tên mới cho một kiểu. Typealias chỉ là một từ đồng nghĩa: một biến kiểu UserId = Long chấp nhận bất kỳ Long nào mà không kiểm tra. Inline class bao bọc một giá trị trong một kiểu mới được kiểm tra lúc biên dịch: không thể truyền một Long đơn giản vào nơi mà một inline class UserId được mong đợi nếu không có chuyển đổi tường minh.

Đặc điểmTypealiasInline class
Kiểu mớiKhông — từ đồng nghĩa của bản gốcCó — kiểu mới với kiểm tra
Hiệu suấtKhông — bị xóa hoàn toànKhông — bao bọc được loại bỏ trong bytecode
Kế thừaKhôngKhông (lớp cuối cùng)
Phương thức riêngKhôngCó — có thể khai báo hàm
An toàn kiểuKhông — có thể thay thế cho bản gốcCó — trình biên dịch phân biệt kiểu

Bảng thể hiện sự khác biệt giữa hai cơ chế. Typealias phù hợp cho các tên ngắn gọn và tài liệu mã khi không cần kiểu chặt chẽ. Inline class thông qua từ khóa value class (trước đây là inline class) cần thiết khi cần phân biệt các giá trị khác nhau về mặt ngữ nghĩa của cùng một kiểu nguyên thủy. Ví dụ, UserId và OrderId đều là Long, nhưng truyền cái này vào nơi mong đợi cái kia là một lỗi logic mà value class ngăn chặn ngay từ lúc biên dịch.

Các câu hỏi thường gặp

Typealias khác gì so với import alias?

Import alias (import com.example.LongName as Short) hoạt động ở cấp độ nhập khẩu — nó rút ngắn tên chỉ trong tệp hiện tại. Typealias khai báo một bí danh toàn cục có sẵn trong toàn bộ dự án sau khi nhập.

Có thể sử dụng typealias để tạo kiểu đệ quy không?

Có, typealias hỗ trợ định nghĩa đệ quy cho các kiểu hàm, nhưng cẩn thận: typealias Rec = (T) -> Rec hoạt động, nhưng tham chiếu đệ quy đến object thì không. Trình biên dịch kiểm tra vòng lặp và báo lỗi cho các định nghĩa vô hạn.

Typealias có ảnh hưởng đến hiệu suất không?

Không, typealias bị xóa hoàn toàn trong quá trình biên dịch. Kiểu gốc được sử dụng ở cấp bytecode và runtime mà không có bao bọc nào. Hiệu suất giống hệt như sử dụng trực tiếp kiểu gốc.

Mức độ lồng nhau tối đa cho typealias là bao nhiêu?

Typealias có thể tham chiếu đến một typealias khác — được gọi là chuỗi bí danh. Độ sâu của chuỗi không bị giới hạn chính thức, nhưng để dễ đọc, không nên quá 2–3 cấp. Trình biên dịch giải quyết hoàn toàn chuỗi trong giai đoạn phân tích.

Có thể khai báo typealias bên trong một hàm không?

Không, typealias là khai báo ở cấp cao nhất hoặc thành viên của một lớp/đối tượng. Typealias không thể được khai báo trong các hàm. Để rút ngắn kiểu cục bộ, hãy sử dụng import alias trong tệp hoặc đặt typealias ở cấp mô-đun.

Tổng kết

  • Typealias — một từ đồng nghĩa cho kiểu hiện có, không tạo kiểu mới và bị xóa trong quá trình biên dịch
  • Kiểu hàm — trường hợp sử dụng chính: typealias thay thế (T) -> R bằng tên dễ đọc như Callback
  • Generic trong typealias cho phép tạo bí danh tổng quát Mapper cho mọi kiểu
  • Lớp lồng nhau — typealias rút ngắn truy cập vào các kiểu lồng nhau sâu và tên dài từ thư viện
  • An toàn kiểu không có: typealias có thể thay thế hoàn toàn cho kiểu gốc
  • Value class — một thay thế cho typealias khi cần kiểm tra kiểu nghiêm ngặt với chi phí runtime bằng không
  • Khả năng đọc — lợi thế chính: các tên kiểu có ý nghĩa làm cho mã tự được tài liệu hóa mà không có chi phí

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm