ankushg
11/18/2021, 7:30 AMexternal interface
definition) that gets exported as a JS/TS Map
with specific key/value types?Big Chungus
11/18/2021, 8:21 AMankushg
11/18/2021, 3:10 PMKotlin collections (List, Set, Map, and so on) are not mapped to any specific JavaScript type.I think what I really want is Index Signatures: https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures Record is similar to that though so it might be a good option
Big Chungus
11/18/2021, 3:12 PMankushg
11/18/2021, 3:59 PMankushg
11/18/2021, 4:20 PMRecord<string, number>
then TS assumes that any string you put in will emit a non-null number.
I think I instead want a Partial<Record<string, number>>
Big Chungus
11/18/2021, 4:23 PMPartial<Record<string, number>> == Record<string, number | undefined>
// Which in kotlin could be expressed as either `external interface Record<String, dynamic>` or `external interface Record<String, Number?>`
ankushg
11/18/2021, 4:27 PMankushg
11/18/2021, 9:48 PMRecord<K, V>
has required keys, and is supposed to be exhaustive over K
Partial<Record<K, V>>
has optional (not just nullable) keys.
My goal was to extend my types by replacing K
with a type within my TS codebase, but using Record
wasn't happy because it was forcing me to be exhaustive in TS
I was able to work around it by just defining an
• external interface Partial<T>
and
• typealias JsMapLikeObject<K, V> = Partial<Record<K, V>>
Big Chungus
11/18/2021, 9:51 PMshaktiman_droid
01/19/2022, 9:57 PMkotlin.collections.Map<>
in d.ts
file to something that would work in TS
?
In our case, we use kotlinx.serialization
and we have a JsExported
data class which has a Map
object. We're struggling to make this work for all platforms smoothly, and we're defining this class in commonMain
sourceSet.shaktiman_droid
01/19/2022, 9:58 PMkotlin.js.Promise
where it shows up in generated TS definition file but typescript compilation errors out because it can't find kotlin.js.Promise
. Replacing it with just Promise
worksankushg
01/19/2022, 10:08 PMshaktiman_droid
01/19/2022, 10:13 PMcommonMain
@JsExport
@Serializable
data class Xyz(val map: Map<String, String>)
it would show up as map: kotlin.collections.Map
in d.ts
fileshaktiman_droid
01/19/2022, 10:14 PMJsMain
with JsExport
then I can convert kotlin Map into Record
using your gist codeankushg
01/21/2022, 7:00 PMshaktiman_droid
01/21/2022, 7:03 PMshaktiman_droid
01/21/2022, 7:03 PMBig Chungus
01/21/2022, 7:06 PMankushg
01/21/2022, 7:06 PMany
or unknown
or something?ankushg
01/21/2022, 7:07 PMPartial<Record<K, V>>
approach enforces some amount of typed-map-like behavior when consuming in TS, but would love to drop it if there’s a better way to do it 🙂Big Chungus
01/21/2022, 7:22 PMankushg
01/21/2022, 8:48 PMRecord
, there’s a sneaky assumption that every key will return a value, which doesn’t match how a Map works.
With a Kotlin or JS Map, myMap[someKey]
returns a nullable/optional type if someKey
isn’t in the map
With a TS Record
type, every myRecord[someKey]
is expected to always have a non-null matching value. The TS typechecker not only doesn’t tell you to null-check the value, but it actively discourages you from trying to null-check it, which can easily crop up some bugs
The reason I use Partial<Record<K, V>>
is so because that exposes a type with map-like semantics, so the TS consumer is expected to actually null-check when accessing a key from the mapBig Chungus
01/21/2022, 10:00 PMBig Chungus
01/21/2022, 10:00 PM