What is starProjectedType, and when would you use it instead of typeOf<T>()?
answer
- starProjectedType: KClass -> KType with all params as *
- List::class.starProjectedType == List<*>
- Use when you only have a KClass at runtime, no real args
- Needs kotlin-reflect; typeOf basic use does not
- Result is never marked nullable
basics
~20 sstarProjectedType turns a KClass into a KType where every generic parameter is replaced by a star (*), meaning 'unknown'. You use it when you have a KClass at runtime but no concrete type arguments to fill in.
solid answer
~40 sKClass<*>.starProjectedType is an extension property (kotlin.reflect.full) that produces a KType for that class with each type parameter replaced by a star projection (*) — e.g. List::class.starProjectedType is List<*>. You reach for it when you hold only a KClass (say, obtained dynamically from an instance via ::class) and must produce a KType, but you have no real type arguments. By contrast typeOf<T>() yields a fully resolved KType including concrete arguments and nullability, and requires the type to be statically known (often via reified). Note starProjectedType lives in kotlin-reflect's full API, so it needs the kotlin-reflect dependency, whereas basic typeOf does not. The resulting type is never marked nullable. For a class with no type parameters, starProjectedType is just that class as a KType (e.g. String::class.starProjectedType == typeOf<String>()).
code
kotlin · 10 linesimport kotlin.reflect.full.starProjectedType
import kotlin.reflect.typeOf
fun main() {
println(List::class.starProjectedType) // List<*>
println(String::class.starProjectedType == typeOf<String>()) // true (no type params)
// From an instance you lost the argument to erasure:
val xs: List<String> = listOf("a")
println((xs::class).starProjectedType) // List<*>, not List<String>
}go deeper
Recognizes starProjectedType fills generics with stars to make a KType from a KClass.
Knows when to choose it over typeOf and that it loses concrete arguments.
Explains the erasure rationale, the kotlin-reflect dependency, and never-nullable result.
Designs reflection-based subtype/registry logic choosing between typeOf, KClass, and starProjectedType with the dependency and erasure trade-offs in mind.
## What starProjectedType produces `val KClass<*>.starProjectedType: KType` (in `kotlin.reflect.full`) returns a `KType` for the class where **every** type parameter is filled with a **star projection** (`*`). A star projection means 'some unknown type argument' — the safe, information-free stand-in. ```kotlin import kotlin.reflect.full.starProjectedType println(List::class.starProjectedType) // kotlin.collections.List<*> println(Map::class.starProjectedType) // kotlin.collections.Map<*, *> println(String::class.starProjectedType) // kotlin.String (no params -> no stars) ``` ## typeOf vs starProjectedType | | typeOf<T>() | KClass.starProjectedType | |---|---|---| | Input | a statically known type | a runtime KClass | | Type args | concrete (List<String>) | all star (List<*>) | | Nullability | as written (?) | never marked nullable | | Dependency | basic use needs only stdlib | needs kotlin-reflect | Use **typeOf** when the concrete generic type is known at compile time (often forwarded via `reified T`). Use **starProjectedType** when you only have a `KClass` discovered at runtime — for instance `value::class.starProjectedType` — and you cannot know the real type arguments because erasure already discarded them. ```kotlin import kotlin.reflect.full.starProjectedType fun typeFromInstance(value: Any): kotlin.reflect.KType = value::class.starProjectedType // best you can do from an erased instance ``` ## Why it exists Many reflection APIs (e.g. `KCallable.returnType` comparisons, `isSubtypeOf` checks via `kotlin.reflect.full`) want a `KType`, but when you start from a `KClass` you genuinely lack argument information. A star projection is the honest representation of 'this class, arguments unknown' and is also the supertype that any concrete instantiation conforms to for subtype checks. ## Gotchas - It requires **kotlin-reflect** on the classpath; calling it without that artifact throws `KotlinReflectionNotSupportedError` at runtime. - The result is never `isMarkedNullable`; you cannot recover a `?` from a bare `KClass`. - For zero-parameter classes it simply equals the plain `KType` for that class.
- Why can't you recover List<String> from an instance via reflection?JVM erasure removes the argument at runtime; the instance only knows it is a List, so starProjectedType can give at best List<*>.
- Is starProjectedType ever marked nullable?No. A bare KClass has no nullability information, so the produced KType is never marked nullable.
typeOf is a fully addressed envelope (List of String); starProjectedType is one addressed only to 'List, occupant unknown' (List<*>).
saying these in an interview costs you the question
- Claiming starProjectedType recovers concrete type arguments from an instance
- Saying it works without the kotlin-reflect dependency
- Thinking the result can be marked nullable
- Confusing star projection (*) with Any as an explicit argument