Skip to main content

Function type aliases in public API

FUNCTION_TYPE_ALIAS_PUBLIC_API reports public type aliases that expand to a function type.

DiagnosticFUNCTION_TYPE_ALIAS_PUBLIC_API
Default severityError
Gradle propertyfunctionTypeAliasPublicApi
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 internal aliases 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)? and public typealias Some = StringBuilder.() -> Unit are 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

See also