salomonbrys
06/23/2022, 4:33 PMChildrenBuilder (https://github.com/JetBrains/kotlin-wrappers/blob/master/kotlin-react/src/main/kotlin/react/ChildrenBuilder.kt), the ElementType<P>.invoke function declares the generic bounds where P : Props, P : ChildrenBuilder .
I can call this function inside a ChildrenBuilder with, for example, ReactHTML.div.invoke {} (here I put the invoke to be explicit, even though it is not required).
Now, ReactHTML.div is an IntrinsicType<HTMLAttributes<HTMLDivElement>>, which is also an ElementType<HTMLAttributes<HTMLDivElement>> , so the resolution kind of makes sense...
BUT I cannot find anywhere HTMLAttributes implements ChildrenBuilder , which should break the resolution of the ElementType<P>.invoke function. The HTMLAttributes interface implements AriaAttributes, DOMAttributes, PropsWithRef, PropsWithChildren, PropsWithClassName, PropsWithStyle, and Props . How the hell can the Kotlin Compiler agrees that the where clause of the ElementType<P>.invoke function is satisfied ?!?!?
Furthermore, IntelliJ shows the invoke "this" hint as ChildrenBuilder & HTMLAttributes<HTMLDivElement> & Props, when, according to the invoke function signature, it should simply display HTMLAttributes<HTMLDivElement> . Where is the ChildrenBuilder coming from ? What black magic is that ?!?
Oh, and when I ask IntelliJ to explicit the type argument to invoke, it can't! It puts Any, which clearly breaks the where clause. If I try to set myself the type argument with div.invoke<HTMLAttributes<HTMLDivElement>> , then IntelliJ tells me that "Type argument is not within its bounds", which I fully agree with!
Help me, please, I'm losing it 🙃 !Sergei Grishchenko
06/23/2022, 4:39 PMElementType is contravariant by P generic because props is inputsalomonbrys
06/23/2022, 4:42 PMP ?Sergei Grishchenko
06/23/2022, 4:43 PMP is generic to represent props
external interface ElementType<in P : Props>salomonbrys
06/23/2022, 4:44 PMHTMLAttributes<HTMLDivElement>...Sergei Grishchenko
06/23/2022, 4:44 PMSergei Grishchenko
06/23/2022, 4:46 PMElementType is FunctionComponent , FunctionComponent is opaque alias to (Props) -> ReactNode? so as you may heard all functions are covariant by return type and contravariant by parameterssalomonbrys
06/23/2022, 4:48 PMSergei Grishchenko
06/23/2022, 4:51 PMFunctionComponent is declared approximately this way
type FC<P> = (props: P) -> ReactNodeSergei Grishchenko
06/23/2022, 4:52 PMFunctionComponent can be invoked, but the rest contract is the samesalomonbrys
06/23/2022, 4:53 PMHTMLAttributes<HTMLDivElement> (since it does not implement ChildrenBuilder, and IDEA can't explicit the type argument to the invoke function, so what can it be ?Sergei Grishchenko
06/23/2022, 4:57 PMP .
Are you asking about this signature?
operator fun <P> ElementType<P>.invoke(
block: @ReactDsl P.() -> Unit,
) where P : Props,
P : ChildrenBuildersalomonbrys
06/23/2022, 4:59 PMSergei Grishchenko
06/23/2022, 5:08 PMthis: IntrinsicType<HTMLAttributes<HTMLDivElement>> your P is HTMLAttributes<HTMLDivElement> but because ElementType is contravariant by P , clause where P : Props, P : ChildrenBuilder it is not upper bound, it is lower bound, you can pass in invoke function any ElementType whose generic type is Props & ChildrenBuilder or more abstract, so you can pass there ElementType<Props> , ElementType<ChildrenBuilder> or ElementType<HTMLAttributes<HTMLDivElement>>Sergei Grishchenko
06/23/2022, 5:11 PMProps & ChildrenBuilder is subtype for Props and for ChildrenBuilderSergei Grishchenko
06/23/2022, 5:22 PMinterface Parent
interface Child : Parent
typealias Task = (Child) -> Unit
fun doWork(task: Task) {
task(object : Child {})
}
fun main() {
val parentTask = { _: Parent -> }
val childTask = { _: Child -> }
doWork(childTask)
doWork(parentTask)
}salomonbrys
06/24/2022, 12:52 PMSergei Grishchenko
06/24/2022, 12:59 PMinterface Props
interface PropsAndChildrenBuilder : Props
typealias ElementType = (PropsAndChildrenBuilder) -> Unit
fun createElement(elementType: ElementType) {
elementType(object : PropsAndChildrenBuilder {})
}
fun main() {
val regularFC = { _: Props -> }
val syntaticFC = { _: PropsAndChildrenBuilder -> }
createElement(regularFC)
createElement(syntaticFC)
}Sergei Grishchenko
06/24/2022, 1:00 PMSergei Grishchenko
06/24/2022, 1:04 PMcreateElement receives only strange ElementType with PropsAndChildrenBuilder arg, but in fact when you pass ElementType<Props> it is also fine for createElementSergei Grishchenko
06/24/2022, 1:07 PMIntrinsicType<HTMLAttributes<HTMLDivElement>> to invoke , it seems than invoke receives only something like that IntrinsicType<HTMLAttributes<HTMLDivElement> & ChildrenBuilder> but in fact IntrinsicType<HTMLAttributes<HTMLDivElement>> is also ok for invoke paramsalomonbrys
06/24/2022, 1:10 PMSergei Grishchenko
06/24/2022, 1:12 PMsalomonbrys
06/24/2022, 1:12 PMsalomonbrys
06/24/2022, 1:13 PMsalomonbrys
06/24/2022, 1:13 PMSergei Grishchenko
06/24/2022, 1:25 PM(T) -> R in Kotlin refers to internal type
interface Function1<in T, out R> , so you can declare you own types with contravariance,
so even ElementType<in P: Props> is not lambda type, it is contravarint by it's P generic, you can treat ElementType as "something abstract that receives props P as input"