Skip to main content

Inline value classes

Value classes are transformed to type aliases. The type of the value class is used.

@Serializable
@JvmInline
value class AuthToken(private val token: String)

fun main() {
val tsGenerator = KxsTsGenerator()
println(tsGenerator.generate(AuthToken.serializer()))
}

You can get the full code here.

export type AuthToken = string;

Value classes from other libraries are also transformed to their inner types. For example, Kotlin unsigned numbers.

import kotlinx.serialization.builtins.serializer

fun main() {
val tsGenerator = KxsTsGenerator()
println(
tsGenerator.generate(
UByte.serializer(),
UShort.serializer(),
UInt.serializer(),
ULong.serializer(),
)
)
}

You can get the full code here.

export type UByte = number;

export type UShort = number;

export type UInt = number;

export type ULong = number;

This weakens the unsigned numbers, and the generated TypeScript could be used to produce incompatible numeric values.

Brand typing

To make value classes a little more strict, we can use brand typing

import dev.adamko.kxstsgen.KxsTsConfig.TypeAliasTypingConfig.BrandTyping
import kotlinx.serialization.builtins.serializer

fun main() {

val tsConfig = KxsTsConfig(typeAliasTyping = BrandTyping)

val tsGenerator = KxsTsGenerator(config = tsConfig)
println(
tsGenerator.generate(
ULong.serializer(),
)
)
}

You can get the full code here.

export type ULong = number & { __ULong__: void };

Now numeric types must be manually converted type aliases.

This does not mean

Nested value classes

If the value class contains another value class, then the outer class will be aliased to other value class

@Serializable
@JvmInline
value class UserCount(private val count: UInt)

fun main() {
val tsGenerator = KxsTsGenerator()
println(tsGenerator.generate(UserCount.serializer()))
}

You can get the full code here.

export type UserCount = UInt;

export type UInt = number;