Hey, is there a guide on how to write wrappers? I ...
# javascript
h
Hey, is there a guide on how to write wrappers? I really want to use the 'zustand' typescript library, but I don't know typescript and am unable to translate some of the syntax into kotlin. I tried Dukat, but it doesn't work on the important file (react.ts) since it's been outdated for so long I presume.
r
h
Thank you.
e
Use Dukat to generate the initial types, even if not perfect. And then fix them manually. Separate the project's wrappers into their own module, and at some point you could even push them to kotlin-wrappers.
h
Is there an option to output in case of an error? Or do you mean to break up the .ts file by hand and generate snippet by snippet? Currently it crashes with
unknown TopLevelEntity
e
I don't think Dukat was ever meant to work on .ts files. It was meant to work on d.ts files.
h
I looked it up, if d.ts only contains declarations, I could try to write my own d.ts that only contains the declarations and try to generate from those.
a
Dukat is nice, if it works! If it's not working then I'd recommend just focusing on writing a wrapper for the bare minimum proof-of-concept first. The wrappers don't have to be comprehensive, just focus on a single function to get started. Looking at the TypeScript guide that would be the
create()
function. Have you written anything for that so far? Can you share it here?
e
Yeah write the bare minimum you need at first. Don't lose too much time.
h
Yes I also indentified create as the first thing I should wrap, but I was already at a loss at the
[]
type and then wandered off to Dukat. My first assumption was that it's the kotlin equivalent to
Array
, but I'd have to look that up to be sure.
a
yeah I'm scanning through the code and generally I see lots of complicated TypeScript types!
h
Yeah, since I have no typescript knowledge that really discouraged me.
a
fortunately K/JS has
dynamic
, so if you ever see a type that's confusing, just use
dynamic
and try and come back to it later. Maybe it can be represented with an external type, but maybe it needs something more complicated,
✔️ 1
e
Using
Any
instead of
dynamic
seems to be the general consensus for wrappers.
h
Thank you, do you know if there is a substantial difference between wrapping typescript and wrapping javascript? In terms of declaration?
e
It's easier to wrap TypeScript as you get the types already, but keep in mind in the end you're just wrapping JS again
plus1 1
a
I find writing wrappers for TypeScript 100 times easier, because it's closer to Kotlin and usually more strongly typed. JS is a wild west.
h
So it's the same
@JsModule
annonations and such?
a
yes, it doesn't matter if the library is written in JS or TS, the Kotlin wrappers are the same because the underlying code will be JS
h
Thanks both of you for your help. It's greatly appreciated.
a
happy to help! If you get stuck on something, feel free to ask and share some code
h
So I started with the create and just did a simple
Copy code
external fun create(createState: dynamic): dynamic
and used it like so:
Copy code
val useTestStore = create({
    var test = "test"
})
So far so good, no errors, but the variable declaration is probably wrong. Trying to get the value again I used:
Copy code
val test = useTestStore {
    it.asDynamic().test
}
println("test: $test")
When I run it I get
test: undefined
So since I want to use Interfaces eventually anyway I figured I need to at least Wrap the
StateCreator
and pass a type. But that's where I can't figure out how to go on.
StateCreator is defined as
Copy code
export type StateCreator<
  T,
  Mis extends [StoreMutatorIdentifier, unknown][] = [],
  Mos extends [StoreMutatorIdentifier, unknown][] = [],
  U = T,
> = ((
  setState: Get<Mutate<StoreApi<T>, Mis>, 'setState', never>,
  getState: Get<Mutate<StoreApi<T>, Mis>, 'getState', never>,
  store: Mutate<StoreApi<T>, Mis>
) => U) & { $$storeMutators?: Mos }
I assume this is the way?
Copy code
external fun <T>create(createState: dynamic): dynamic
external class StateCreator<T, Mis, Mos> {
    fun setState(): dynamic
    fun getState(): dynamic
    fun store(): dynamic
}
But now the interface is not referenced anywhere in the create function which of course gives me an error here:
Copy code
interface testInterface {
    var test: String
}
val useTestStore = create<testInterface>({
    test = "test" // var test unknown
})
a
It looks like StateCreator is 'type', which would be represented as an
external interface
, not an
external class
h
Ah, thank you. The error on var unknow is indeed gone now.
a
oh nice, I didn't expect that haha, but good that it works
h
I still get
undefined
when trying to get the state though
a
I think these properties of StateCreator
Copy code
setState: Get<Mutate<StoreApi<T>, Mis>, 'setState', never>,
  getState: Get<Mutate<StoreApi<T>, Mis>, 'getState', never>,
  store: Mutate<StoreApi<T>, Mis>
should be mapped to Kotlin vals, or most likely vars
I'm really struggling to see how to properly write wrappers though 😬. Are you sure you want to use zustand...?
I think
create
isn't mapped to a function, it's mapped to a val 🤯
Copy code
export const create = (<T>(createState: StateCreator<T, [], []> | undefined) =>
  createState ? createImpl(createState) : createImpl) as Create
and the type,
Create
, has a function that you invoke
e
Copy code
Get<Mutate<StoreApi<T>, Mis>, 'setState', never>
The beautiful TS type system lmao But this would get translated to
Copy code
Get<Mutate<StoreApi<T>, Mis>, String, Nothing>
Remember that sometimes 1:1 mapping is not possible. `external`s let you implement logic if you want
You may have to resort to
asDynamic
sometimes.
h
Sorry, I had a meeting. Thank you all for your input. About using zustand, we wanted to look if it's possible to avoid redux due to a coworker saying it's a bit bloated and our needs are essentially just to have a global state for a few minor things. So I thought I take a shot at a wrapper to learn in general and maybe even get a working wrapper out of it. The way I see it in most cases you only need to make a superficial wrap of the immediately jused functions/types. So it sounded "not so bad" 😄
"oh nice, I didn't expect that haha, but good that it works" It weirdly worked and I even build it, but now it's not working anymore. Very weird.
e
@Hildebrandt Tobias don't be discouraged. If you've got a bit of time to spend on that topic, experiment. Also check kotlin-wrappers on GitHub for ideas.
h
Really struggling with the StateCreator. I think
export const create = (<T>(createState: StateCreator<T, [], []> | undefined) =>  createState ? createImpl(createState) : createImpl) as Create
is a function reference inside a val. The StateCreator is
type
which is a
typealias
but the type is a function that sets three values setState, getState and store and returns as the generic T? ``````
Man this is soul crushing when you are poking in the dark like this. I think the create function looks like this
external fun <T>create(block: (StateCreator<T, Nothing, Nothing>) -> T): dynamic
e
I'll give a look at the TS code later this evening
h
That would be greatly appreciated. I think the relevant parts are in https://github.com/pmndrs/zustand/blob/main/src/react.ts and https://github.com/pmndrs/zustand/blob/main/src/vanilla.ts I will try to poke around a little more.