Function type aliases in public API
FUNCTION_TYPE_ALIAS_PUBLIC_API reports public type aliases that expand to a function type.
| Diagnostic | FUNCTION_TYPE_ALIAS_PUBLIC_API |
| Default severity | Error |
| Gradle property | functionTypeAliasPublicApi |
| Exemption | @IntentionallyFunctionTypeAlias |
What it reports
A public or protected type alias whose expanded type is a function type: plain, suspend,
nullable, or with a receiver.
/** Handles progress updates emitted by background work. */public typealias ProgressHandler = (Int) -> Unit
Rationale
A type alias is not a real type: it is erased at compile time, so a user compiled against
Callback really binds to (Int) -> Unit. The alias can never grow a second member, a default
implementation, or additional constraints. The only way to change the shape later is a breaking
change to the bare function type. A
fun interface
keeps the same lambda call-site ergonomics (SAM conversion) behind a real type that can
add default members without breaking binary compatibility, or be extended from.
Don't
/** Receives completed work percentages. */public typealias Callback = (Int) -> Unit
Do
/** Receives completed work percentages. */@IntentionallyOpen(reason = ExemptionReason.API_DESIGN)public fun interface Callback {/** Reports that [value] percent of the work is complete. */public fun onCall(value: Int)}
Don't
/** Represents an operation that may suspend. */public typealias SuspendAction = suspend () -> Unit
Do
/** Represents an operation that may suspend. */@IntentionallyOpen(reason = ExemptionReason.API_DESIGN)public fun interface SuspendAction {/** Executes the operation. */public suspend fun invoke()}
Notes
@PublishedApi internalaliases are not reported because library users cannot name them in source, and an alias contributes no binary declaration of its own.- Nullable and receiver variants are caught the same way:
public typealias Some = ((String) -> Boolean)?andpublic typealias Some = StringBuilder.() -> Unitare both function types under the alias. - A function type nested inside another type, such as
List<(Int) -> Unit>, doesn't trigger the check, only the type an alias directly expands to counts.
Exemption
Apply @IntentionallyFunctionTypeAlias when exposing the bare function type is intended.
/** Receives completed work percentages through a deliberately bare function shape. */@IntentionallyFunctionTypeAlias(reason = ExemptionReason.API_DESIGN)public typealias Callback = (Int) -> Unit
Configuration
apiWatchdog {functionTypeAliasPublicApi = WatchdogSeverity.WARNING}
With direct compiler invocation:
-P plugin:org.jetbrains.kotlin.library.api.watchdog:diagnosticSeverity=FUNCTION_TYPE_ALIAS_PUBLIC_API:warning