or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

builder-dsl.mdconfiguration.mdcore-operations.mdcustom-serializers.mddynamic-conversion.mdindex.mdjson-annotations.mdjson-element.md

dynamic-conversion.mddocs/

0

# JavaScript Dynamic Conversion

1

2

JavaScript-specific functionality for converting between Kotlin objects and native JavaScript objects with full type safety. These APIs enable seamless interoperability with JavaScript code while maintaining Kotlin's type system.

3

4

## Capabilities

5

6

### Dynamic Encoding

7

8

Convert Kotlin objects to JavaScript dynamic objects for seamless JavaScript interop.

9

10

```kotlin { .api }

11

/**

12

* Converts Kotlin data structures to plain JavaScript objects

13

* @param serializer Serialization strategy for type T

14

* @param value The Kotlin value to convert

15

* @return JavaScript dynamic object

16

*/

17

@ExperimentalSerializationApi

18

fun <T> Json.encodeToDynamic(serializer: SerializationStrategy<T>, value: T): dynamic

19

20

/**

21

* Converts Kotlin data structures to plain JavaScript objects using reified type

22

* @param value The Kotlin value to convert

23

* @return JavaScript dynamic object

24

*/

25

@ExperimentalSerializationApi

26

inline fun <reified T> Json.encodeToDynamic(value: T): dynamic

27

```

28

29

**Usage Examples:**

30

31

```kotlin

32

@Serializable

33

data class UserProfile(

34

val name: String,

35

val age: Int,

36

val isActive: Boolean,

37

val scores: List<Double>

38

)

39

40

val json = Json.Default

41

val profile = UserProfile("Alice", 25, true, listOf(85.5, 92.0, 78.3))

42

43

// Convert to JavaScript object

44

val jsObject = json.encodeToDynamic(profile)

45

46

// Use in JavaScript interop

47

console.log(jsObject.name) // "Alice"

48

console.log(jsObject.age) // 25

49

console.log(jsObject.isActive) // true

50

console.log(jsObject.scores) // JavaScript Array [85.5, 92.0, 78.3]

51

52

// Can be passed to JavaScript functions expecting plain objects

53

someJsFunction(jsObject)

54

```

55

56

### Dynamic Decoding

57

58

Convert JavaScript objects to typed Kotlin objects with full validation.

59

60

```kotlin { .api }

61

/**

62

* Converts native JavaScript objects into Kotlin ones, verifying their types

63

* @param deserializer Deserialization strategy for type T

64

* @param dynamic JavaScript object to convert

65

* @return Typed Kotlin object

66

* @throws JsonDecodingException if dynamic object structure is invalid

67

*/

68

@ExperimentalSerializationApi

69

fun <T> Json.decodeFromDynamic(deserializer: DeserializationStrategy<T>, dynamic: dynamic): T

70

71

/**

72

* Converts native JavaScript objects into Kotlin ones using reified type

73

* @param dynamic JavaScript object to convert

74

* @return Typed Kotlin object

75

* @throws JsonDecodingException if dynamic object structure is invalid

76

*/

77

@ExperimentalSerializationApi

78

inline fun <reified T> Json.decodeFromDynamic(dynamic: dynamic): T

79

```

80

81

**Usage Examples:**

82

83

```kotlin

84

// JavaScript object created in JS code

85

val jsData: dynamic = js("""{

86

name: "Bob",

87

age: 30,

88

isActive: false,

89

scores: [90.5, 88.0, 95.2]

90

}""")

91

92

// Convert to typed Kotlin object

93

val profile = json.decodeFromDynamic<UserProfile>(jsData)

94

95

println(profile.name) // "Bob"

96

println(profile.age) // 30

97

println(profile.isActive) // false

98

println(profile.scores) // [90.5, 88.0, 95.2]

99

100

// Works with objects received from JavaScript APIs

101

fun processApiResponse(response: dynamic) {

102

try {

103

val user = json.decodeFromDynamic<UserProfile>(response)

104

// Use typed object safely

105

updateUI(user)

106

} catch (e: JsonDecodingException) {

107

handleInvalidResponse(e)

108

}

109

}

110

```

111

112

## JavaScript Interoperability

113

114

### Data Type Conversions

115

116

Dynamic conversion handles JavaScript type mappings automatically:

117

118

```kotlin

119

@Serializable

120

data class TypeExample(

121

val stringVal: String,

122

val intVal: Int,

123

val boolVal: Boolean,

124

val doubleVal: Double,

125

val listVal: List<String>,

126

val mapVal: Map<String, Int>

127

)

128

129

val kotlinObj = TypeExample(

130

stringVal = "hello",

131

intVal = 42,

132

boolVal = true,

133

doubleVal = 3.14,

134

listVal = listOf("a", "b", "c"),

135

mapVal = mapOf("x" to 1, "y" to 2)

136

)

137

138

val jsObj = json.encodeToDynamic(kotlinObj)

139

// JavaScript object with native JS types:

140

// {

141

// stringVal: "hello",

142

// intVal: 42,

143

// boolVal: true,

144

// doubleVal: 3.14,

145

// listVal: ["a", "b", "c"],

146

// mapVal: {x: 1, y: 2}

147

// }

148

```

149

150

### Nested Objects

151

152

Dynamic conversion works recursively with nested structures:

153

154

```kotlin

155

@Serializable

156

data class Address(val street: String, val city: String)

157

158

@Serializable

159

data class Person(

160

val name: String,

161

val address: Address,

162

val contacts: List<String>

163

)

164

165

val person = Person(

166

name = "Charlie",

167

address = Address("123 Main St", "Anytown"),

168

contacts = listOf("email@example.com", "555-1234")

169

)

170

171

val jsObj = json.encodeToDynamic(person)

172

// Nested JavaScript object:

173

// {

174

// name: "Charlie",

175

// address: {

176

// street: "123 Main St",

177

// city: "Anytown"

178

// },

179

// contacts: ["email@example.com", "555-1234"]

180

// }

181

182

// Convert back to Kotlin

183

val restored = json.decodeFromDynamic<Person>(jsObj)

184

```

185

186

## Limitations and Considerations

187

188

### Long Value Limitations

189

190

JavaScript numbers have precision limitations that affect Long values:

191

192

```kotlin

193

@Serializable

194

data class DataWithLong(val id: Long, val value: String)

195

196

// Safe Long values (within JavaScript's MAX_SAFE_INTEGER)

197

val safeData = DataWithLong(9007199254740991L, "safe")

198

val safeJs = json.encodeToDynamic(safeData) // Works correctly

199

200

// Unsafe Long values (exceed JavaScript precision)

201

val unsafeData = DataWithLong(9007199254740992L, "unsafe")

202

// This may lose precision when converted to JavaScript number

203

204

// Solution: Use String for large Long values

205

@Serializable

206

data class SafeLongData(

207

@Serializable(with = LongAsStringSerializer::class)

208

val id: Long,

209

val value: String

210

)

211

```

212

213

### Map Key Limitations

214

215

Map keys must be primitive types as they're converted to JavaScript object properties:

216

217

```kotlin

218

@Serializable

219

data class ValidMaps(

220

val stringKeys: Map<String, Int>, // ✓ Valid

221

val intKeys: Map<Int, String>, // ✓ Valid (converted to string keys)

222

val enumKeys: Map<Color, String> // ✓ Valid (enum names as keys)

223

)

224

225

@Serializable

226

enum class Color { RED, GREEN, BLUE }

227

228

// Invalid: Complex objects as keys

229

@Serializable

230

data class InvalidMap(

231

val complexKeys: Map<Person, String> // ✗ Invalid - will fail

232

)

233

```

234

235

### Null vs Undefined

236

237

Dynamic conversion preserves JavaScript null/undefined semantics where appropriate:

238

239

```kotlin

240

@Serializable

241

data class NullableData(val name: String, val value: String?)

242

243

val withNull = NullableData("test", null)

244

val jsObj = json.encodeToDynamic(withNull)

245

// JavaScript: {name: "test", value: null}

246

247

val withoutValue = js("{name: 'test'}") // undefined value property

248

val restored = json.decodeFromDynamic<NullableData>(withoutValue)

249

// Results in NullableData("test", null)

250

```

251

252

## Integration with JavaScript APIs

253

254

### Working with JavaScript Promises

255

256

```kotlin

257

// Convert Kotlin object for JavaScript Promise resolution

258

suspend fun fetchUserData(userId: String): dynamic {

259

val userData = getUserFromDatabase(userId)

260

return json.encodeToDynamic(userData)

261

}

262

263

// Handle JavaScript API responses

264

fun handleApiResponse(response: dynamic) {

265

val user = json.decodeFromDynamic<User>(response.data)

266

processUser(user)

267

}

268

```

269

270

### DOM Integration

271

272

```kotlin

273

// Convert data for DOM storage

274

fun saveToLocalStorage(key: String, data: UserPreferences) {

275

val jsData = json.encodeToDynamic(data)

276

localStorage.setItem(key, JSON.stringify(jsData))

277

}

278

279

// Load data from DOM storage

280

fun loadFromLocalStorage(key: String): UserPreferences? {

281

val item = localStorage.getItem(key) ?: return null

282

val jsData = JSON.parse(item)

283

return json.decodeFromDynamic<UserPreferences>(jsData)

284

}

285

```

286

287

### Configuration and Equivalence

288

289

Dynamic conversion behavior respects Json configuration settings:

290

291

```kotlin

292

val lenientJson = Json {

293

isLenient = true

294

ignoreUnknownKeys = true

295

}

296

297

// Both approaches should produce equivalent results

298

val jsonString = """{"name":"Alice","age":25,"extra":"ignored"}"""

299

val fromString = lenientJson.decodeFromString<Person>(jsonString)

300

301

val jsObj = JSON.parse(jsonString)

302

val fromDynamic = lenientJson.decodeFromDynamic<Person>(jsObj)

303

304

// fromString == fromDynamic should be true

305

```