How does typeOf<T>() work, and why is a reified type parameter usually involved?
answer
- typeOf<T>() -> KType, compiler intrinsic
- reified T requires inline fun
- Captures generics; ::class does not
- Basic typeOf needs only stdlib, not full kotlin-reflect
- Powers serializer<T>() patterns
basics
~20 stypeOf<T>() returns the KType for whatever type you put in the angle brackets. To pass a generic type variable T into it from your own function, T must be reified, which only works in an inline function.
solid answer
~40 stypeOf<T>() is a kotlin-reflect-light intrinsic (declared in kotlin.reflect) that returns the full KType for the type argument T, including its generic arguments and nullability — e.g. typeOf<Map<String, List<Int>>>(). With a concrete type you can call it directly. To capture a caller's generic parameter, you write an inline fun with a reified T, because reified makes the actual type available at the call site where the compiler substitutes it. Without reified, T is erased and typeOf<T>() won't compile. Importantly, typeOf is special: it does NOT require the heavy kotlin-reflect artifact for the basic KType, only kotlin-stdlib, although fully resolving some members may. This pattern underpins kotlinx.serialization's reified serializer<T>() and similar APIs. Compared to ::class (a KClass), typeOf<T>() preserves generics that ::class throws away.
code
kotlin · 13 linesimport kotlin.reflect.KType
import kotlin.reflect.typeOf
// reified forwards the concrete type into typeOf at the call site
inline fun <reified T> describe(): String {
val t: KType = typeOf<T>()
return "classifier=${t.classifier}, nullable=${t.isMarkedNullable}, args=${t.arguments}"
}
fun main() {
println(describe<List<String>?>())
// classifier=class kotlin.collections.List, nullable=true, args=[kotlin.String]
}go deeper
Knows typeOf<T>() returns a KType for a concrete type.
Explains the reified + inline requirement and that typeOf preserves generics unlike ::class.
Notes typeOf is a compiler intrinsic working around erasure and that basic use avoids the heavy kotlin-reflect artifact.
Designs generic library APIs (e.g. serializer<T>()) on top of reified typeOf and reasons about the dependency/cost trade-offs.
## What typeOf does `typeOf<T>()` (function in `kotlin.reflect`) returns a `KType` describing the type argument `T` exactly as written, complete with generic arguments and nullability. It is a *compiler intrinsic*: the compiler synthesizes the `KType` at the call site, so it works even though the JVM erases generics. ```kotlin import kotlin.reflect.typeOf val kt = typeOf<Map<String, List<Int>?>>() println(kt) // kotlin.collections.Map<kotlin.String, kotlin.collections.List<kotlin.Int>?> ``` ## Why reified shows up If you try to forward a generic parameter from your own function, the parameter is normally **erased** — the function body has no idea what `T` was. `reified` solves this, but `reified` is only legal on an **inline** function. Inlining copies the body to the call site, where the concrete type is known, so the compiler can substitute the real type into `typeOf`. ```kotlin import kotlin.reflect.KType import kotlin.reflect.typeOf inline fun <reified T> kindOf(): KType = typeOf<T>() val a = kindOf<List<String>>() // List<String> val b = kindOf<Int?>() // Int? ``` Without `reified` (or on a non-inline function) `typeOf<T>()` fails to compile with an error that `T` is not a reified type parameter. ## Dependency cost A key, often-missed detail: `typeOf<T>()` for obtaining the `KType` works with only **kotlin-stdlib** — it does **not** force you to pull in the full `org.jetbrains.kotlin:kotlin-reflect` jar. Deeper reflective operations (enumerating members, etc.) may still need `kotlin-reflect`, but the type representation itself is lightweight. ## Relationship to ::class `x::class` and `T::class` (reified) yield a `KClass`, which loses generics. `typeOf<T>()` yields a `KType`, which keeps them. Use `typeOf` whenever the generic shape matters (serialization, type-safe deserialization, generic DI containers). ## A common bridge `typeOf<T>().classifier as? KClass<*>` lets you recover the bare class from a KType when you only need the classifier.
- Why can't a non-inline function call typeOf<T>() on its own T?Because non-inline T is erased; reified (only allowed with inline) is what makes the concrete type available to substitute into typeOf.
- Does using typeOf force the kotlin-reflect dependency?No — obtaining a KType via typeOf works with only kotlin-stdlib. Heavier member resolution may need kotlin-reflect.
saying these in an interview costs you the question
- Saying reified works on regular (non-inline) functions
- Claiming typeOf loses generic arguments
- Thinking typeOf is the same as ::class
- Asserting typeOf always pulls in the full kotlin-reflect jar