Verify Generics

Type parameter vs type argument

To undersigned Konsist API let's look at the difference between generic type parameters and generic type arguments:

  1. Type Parameter is the placeholder (like T) you write when creating a class or function (declaration site)

  2. Type Argument is the actual type (like String or Int) you provide when using that class or function (use site)

Simple Examples:

// Example 1: Class
// Here 'T' is a TYPE PARAMETER
class Box<T>(val item: T)

// Here 'String' is a TYPE ARGUMENT
val stringBox = Box<String>("Hello")


// Example 2: Function
// Here 'T' is a TYPE PARAMETER
fun <T> printWithType(item: T) {
    println("Type is: ${item::class.simpleName}")
}

// Here 'String' and 'Int' are TYPE ARGUMENTS
printWithType<String>("Hello")  // prints: Type is: String

Verify Type Parameters

Type parameters can be defined, for example, inside class or function.

Check whether a class's generic type parameter has the name UiState:

// Code Snippet 
class View<UiState>(val state: UiState) // UiState is typeParamener 

// Konsist
Konsist
    .scopeFromProject()
    .classes()
    .typeParameters // access type parameters
    .assertTrue {
        it.name == "UiState" // true
    }

Check whether function type parameters has out modifier:

//Code Snippet 
fun <out T> setState(item: T?) {
    // ...
}

// Konsist
Konsist
    .scopeFromProject()
    .functions()
    .typeParameters // access type parameters
    .assertTrue {
        it.hasOutModifier // true
    }

Verify Type Arguments

Check whether a property generic type argument has the name Service:

//Code Snippet 
val services: List<Service> = emptyList()

// Konsist
Konsist
    .scopeFromProject()
    .properties()
    .assertTrue { property ->
        property
            .type
            ?.typeArguments
            ?.flatten()
            ?.any { typeArgument -> typeArgument.name == "Service" }
    }

The flatten() extension method allows to flatten type parameters structure:

  • For a type argument like String, it returns listOf().

  • For a type argument like List<String>, it returns listOf(String).

  • For a type argument like Map<List<String>, Int>, it returns listOf("List, String, Int).

Check if all functions parameters are have generic type argument ending with UIState:

// Snippet 
fun setState(uiState: View<WelcomeUIState>)

// Konsist Test
Konsist
    .scopeFromProject()
    .properties()
    .parameters
    .types
    .typeArguments
    .assertTrue { 
        it.hasNameEndingWith("UIState")  // true
    }

Check all parents have `String` type argument:

// Snippet 
open class Container<T>(private val item: T) { }
class StringContainer(text: String) : Container<String>(text) { }

// Konsist Test
Konsist
    .scopeFromProject()
    .classes()
    .parents()
    .typeArguments
    .flatten()
    .assertTrue { 
        it.name == "String"  // true
    }

Last updated