I've written a library that will generate TypeScri...
# feed
a
I've written a library that will generate TypeScript interfaces based on Kotlinx Serialization annotated classes! https://github.com/adamko-dev/kotlinx-serialization-typescript-generator This is really helpful for writing TypeScript and Kotlin libraries that communicate via JSON messages. I'm particularly pleased with the sealed class generation - it creates really idiomatic code that's useful at both ends. • work in progress - there are still some rough edges! • It's on Maven Central • it's multiplatform (JVM and JS at the moment)
👍 3
👍🏾 2
👍🏽 1
👍🏻 1
b
How is this different from dukat or kjs .d.ts generation of @JsExport members?
Just trying to understand the aim of the project
a
Good questioin! Dukat, Kotlin/JS, and
@JsExport
are more focused on re-using code. kxs-ts-gen is focused on serialization. It's also a lot more flexible. In Kotlinx Serialization you can define custom serializers, like serializing a colour class
Colour(0, 255, 255, 100)
as a hex string. kxs-ts-gen will automatically take that into account, and generate compatible TypeScript interfaces.
I use it for serializing coordinates as tuples
[0, 2, 10]
is more compact than
{ "x": 0, "y": 2, "z": 10 }
I don't think the above is possible with
@JsExport
j
Are you saying that the generated TS interfaces reflect the format on the wire instead of using a code-friendly structure similar to what is in the Kotlin classes? It seems counterproductive, why would you use those interfaces from TS instead of deserializing to TS interfaces that are more similar to the Kotlin structure?
b
One usecase is having ts frontend without using kotlin.js
To avoid the bloat that comes with it
TS interfaces are erased and thus "free", however kotlin interfaces still carry some metadata and as such are not free
j
Still, if you use a TS frontend, it will likely need a comfortable format to interact with. The format on the wire should be as irrelevant to the client code as it is to the server code. I would understand if it generated TS interfaces matching the Kotlin ones + deserialization code (it still wouldn't require Kotlin JS nor Kotlin interfaces)
b
Isn't this project simply generating ts interfaces to match json payloads?
👌 1
a
Are you saying that the generated TS interfaces reflect the format on the wire instead of using a code-friendly structure similar to what is in the Kotlin classes?
yes, it generates TS interfaces. I don't know what you mean by 'code friendly structure'? I'm actually using this for a TypeScriptToLua project, so Kotlin/JS isn't an option at all. If I didn't have this tool then I'd have to manually create TypeScript interfaces to match the JSON that the
@Serializable
Kotlin classes produce - which I find error prone and laborious. I looked into generating both TS and Kt from a schema (like OpenAPI) - but nothing was satisfying. It's nice having a Kotlin-first approach. kxs-ts-gen is re-treading ground - ProtoBufSchemaGenerator does the same thing
j
Sorry if I wasn't clear. I understand the goal of this library, and the fact that it generates TS interfaces to match the JSON on the wire. My point was that the way the Kotlin declarations are designed is meant to be easy to use from the code's perspective: for instance
x, y, z
properties for a 3D point, or an enum type to repesent a set of possible values. When the wire format is different (e.g. an array for the 3D point, or integers for the enum), it's usually because it's more optimal for transport, but it's never because it's easier to work with from the code (otherwise the Kotlin declaration would be just changed to that other format). So my point is, the initial declarations in Kotlin code are either equal or better-suited for usage from code than the wire format, so if you could better match the initial Kotlin declarations in your TS definitions, it would usually be better from the consumer's perspective. This, of course, means that you do need deserialization facilities to convert from the wire format to those "better" TS interfaces. Representing the wire format is easier of course, and might be "good enough" for some use cases. This is probably what justifies the simplification of just representing a suboptimal wire format in code without deserialization code. However, in the extreme case where a lot of custom serialization is used to reduce the payload, the wire format will be really uncomfortable to use from TS. That said, maybe this extreme case is just theoretical, and people interested in optimizing that much would just use a more efficient binary format like proto
n
The way I understand the motivation of this project, representing the wire format is the point. You can always take the wire format and apply transforms to it in typescript to make it more usable, and those transforms will already be type safe assuming you know what the wire format was. A tool like this would allow you to generate the contract of your API directly into typescript, giving you the "before" types for those transforms (or the "after" for inbound types).
👍 1