Kotlin typealias

The typealias can be handy to define very simple types. But be aware that it is not represented in bytecode — typealiases are simply replaced by the type they represent during compilation, and so can’t be used to distinguish between different aliased types in function signatures.

This also has consequences for dependency injection. When bean injection relies on naming and that bean gets renamed, Spring may silently inject an alternative based on type matching, leading to unexpected behaviour.

import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean

typealias TypeOne = String
typealias TypeTwo = String

typealias SignatureOne = () -> String
typealias SignatureTwo = () -> String

@SpringBootTest
class ExperimentMilo {
    @TestConfiguration
    class TestConfig {
        @Bean
        fun funOne(): SignatureOne = { "FunOne" }

        @Bean
        fun funTwo(): SignatureTwo = { "FunTwo" }
    }

    @Autowired lateinit var funOne: SignatureOne
    @Autowired lateinit var funTwo: SignatureTwo

    @Autowired @Qualifier("funOne") lateinit var functionOne: SignatureOne
    @Autowired @Qualifier("funTwo") lateinit var functionTwo: SignatureTwo

    @Test
    fun testBeanSignature() {
        val resultOne = funOne.invoke()
        val resultTwo = funTwo.invoke()

        Assertions.assertEquals("FunOne", resultOne)
        Assertions.assertEquals("FunTwo", resultTwo)
    }

    @Test
    fun testBeanSignature2() {
        val resultOne = functionOne.invoke()
        val resultTwo = functionTwo.invoke()

        Assertions.assertEquals("FunOne", resultOne)
        Assertions.assertEquals("FunTwo", resultTwo)
    }

    @Test
    fun testFunctionSignature() {
        val one: TypeOne = "One"
        val two: TypeTwo = "Two"

        val resultOneTwo = testSignature(one, two)
        val resultTwoOne = testSignature(two, one)

        Assertions.assertEquals(Pair("One", "Two"), resultOneTwo)
        Assertions.assertEquals(Pair("Two", "One"), resultTwoOne)
    }

    fun testSignature(one: TypeOne, two: TypeTwo): Pair<TypeOne, TypeTwo> {
        return Pair(one, two)
    }
}

More information in the official Kotlin documentation on type aliases.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *