Currently we're not handling null/undefined at all. One way we could is to make 3 new typeclass instances (one for A | Null, one for A | Unit, and one for A | Null | Unit).
For example:
given [A](using nc: NativeConverter[A]): NativeConverter[A | Null | Unit] with
extension (t: A | Null | Unit) def toNative: js.Any =
if t == null || t == () then t.asInstanceOf[js.Any]
else nc.toNative(t.asInstanceOf[A]) // if there was flow-typing for Unit there would be no need to cast :'(
def fromNative(nativeJs: js.Any): A | Null | Unit =
if nativeJs == null || js.isUndefined(nativeJs) then nativeJs.asInstanceOf[Null | Unit]
else nc.fromNative(nativeJs)
val nc3 = NativeConverter[Int | Null | Unit]
assertTrue(nativeNull == nc3.toNative(null))
assertTrue(js.undefined == nc3.toNative(()))
assertTrue(JSON.parse("5") == nc3.toNative(5))
assertTrue(null == nc3.fromNative(nativeNull))
assertTrue(() == nc3.fromNative(js.undefined))
assertTrue(5 == nc3.fromNative(JSON.parse("5")))
case class C(c: Int | Null | Unit) derives NativeConverter
val nullC = C(null)
assertEquals(""" {"c":null} """.trim, JSON.stringify(nullC.toNative))
assertEquals(nullC, NativeConverter[C].fromNative(JSON.parse(""" {"c":null} """)))
val undefC = C(())
assertEquals(""" {} """.trim, JSON.stringify(undefC.toNative))
assertEquals(undefC, NativeConverter[C].fromNative(JSON.parse(""" {} """)))
val intC = C(123)
assertEquals(""" {"c":123} """.trim, JSON.stringify(intC.toNative))
assertEquals(intC, NativeConverter[C].fromNative(JSON.parse(""" {"c":123} """)))
However, no flow-typing for Unit makes this inconvenient.
lampepfl/dotty-feature-requests#178
Currently we're not handling null/undefined at all. One way we could is to make 3 new typeclass instances (one for A | Null, one for A | Unit, and one for A | Null | Unit).
For example:
However, no flow-typing for Unit makes this inconvenient.
lampepfl/dotty-feature-requests#178