Is it possible to get something similar to union t...
# javascript
q
Is it possible to get something similar to union types in Typescript? I'm trying to use
sealed interface
but if I add the
external
modifier then it doesn't enforce strict typing. What I'd like is:
Copy code
sealed interface Element

external interface Object : Element {
  val properties: Record<String, Element>
}

external interface Primitive {
  val type: Type
  val value: Any?
}

external interface Array : Element {
  val items: Array<Element>
}

// TS
const obj: Element = { properties : { items: { type: Type.string, value: 'something' } } }
But it doesn't work because
Element
is not external. If I make
Element
external though, then it is compatible with
{}
e
"Real" unions will only work with a compiler plugin that understands something like
Copy code
prop: Union<One, Two>
The assignment can be checked so that
Copy code
val one = One()
prop = one // ok
prop = "wrong" // error

val two = Two() 
prop = two // ok
t
Looks like issue In current case I expect
Element
as union in TS, because it's
sealed
q
yeah, I would expect
sealed
to be incompatible with
external
or, I would expect a
sealed interface
not to match an object that doesn't belong to any of the implementations
t
We have multiple sealed external interfaces in wrappers
And yes, they describe unions
TS union -> Kotlin external sealed interface -> TS union
q
created a ticket here
e
I don't really understand what you would expect from an empty interface to be honest.
{}
is perfectly valid for TS perspective. How would you solve it?
q
I'm not saying I've got the perfect design for this, but it doesn't make sense to define an interface as sealed if it's not (at least, not on the JS side). In the case above there is arguably no difference between a sealed external interface and an external interface in TS
e
But what I don't understand is your goal here. Like I'm not getting what you'd like to have in the TS side. Could you make a more practical example?
Sealed is a Kotlin concept for tagged unions, you don't have that in TS
q
Taking the example above:
Copy code
sealed interface Element

external interface Object : Element {
  val properties: Record<String, Element>
}

external interface Primitive {
  val type: Type
  val value: Any?
}

external interface Array : Element {
  val items: Array<Element>
}
what I assumed would be produced is something like:
Copy code
interface Array {
    val items: Element[]
}

interface Object {
    val properties: Record<string, Element>
}

type Element = Array | Object
This would enforce the sealing, so that I can't pass in an empty object as a valid instance of the type
Element
e
Ok now it's a lot more understandable! The case of an empty base interface is easy, but I'm not sure how all the rest of the cases would be handled. But it would be a nice enhancement, indeed.
t
Non-empty sealed interface will work the same way
👍 1
q
@turansky yes, as long as you match the properties in the sealed interface, it is considered valid. The empty object case is just the easiest example