Search code examples
kotlintypesandroid-jetpack-composecomposable

How to type restrict a composable parameter in Jetpack Compose?


I have a function that takes in another Composable function as a parameter:

@Composable
fun MyComposable(
    myParameter: @Composable () -> Unit
) {
    //...
}

I want to restrict myParameter to only accept Button composables. But since Button is a function and not a class, I do not know how to achieve this. So how do I type-restrict composable parameters?


Solution

  • Type-restricting parameters in Kotlin, especially for Composable functions, to accept only certain types of composables (like Button) isn't straightforward or directly supported in the language or Compose framework. This is due to the nature of Composable functions and how they are executed by the Compose runtime.

    Composable functions, like Button, Text, etc., are just functions annotated with @Composable. They don't have a common superclass or interface that you could use for type restriction. When you pass a Composable function as a parameter, what you're actually passing is a lambda function that the Compose runtime will execute within its own context. These functions don't have a return type or a common type that could be used for type checking.

    However, you can design your API in a way that encourages or enforces the use of certain types of Composables through documentation or by structuring your function parameters to match the expected signature of certain Composable functions.

    For example:

    @Composable
    fun MyComposable(
        buttonContent: @Composable () -> Unit
    ) {
        // Using buttonContent within a Button composable
        Button(onClick = { /* ... */ }) {
            buttonContent()
        }
    }
    

    In the above example, buttonContent is a Composable lambda meant to be used inside a Button. By naming the parameter buttonContent, you can indicate that it should be content suitable for a button, like text or an icon. However, this won't prevent someone from passing in a different type of Composable content.

    If you need to enforce this restriction more strictly, you might need to rethink your API design or use a different approach to achieve the desired functionality. One possibility could be creating a custom Composable that wraps a Button and exposes parameters for the specific content you want to allow (like text, icons, etc.), rather than accepting a generic Composable lambda.