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가 코드를 크게 단순화하는 또 다른 영역입니다. 클래스가 중첩 계층 구조(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
새 타입아니요 — 원본의 동의어예 — 검사가 있는 새 타입
성능제로 — 완전히 지워짐제로 — 바이트코드에서 래퍼 제거
상속아니요아니요(최종 클래스)
자체 메서드아니요예 — 함수 선언 가능
타입 안전성아니요 — 원본과 상호 교환 가능예 — 컴파일러가 타입 구별

표는 두 메커니즘의 차이를 보여줍니다. 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 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기