While exploring typescript I noticed that the inference rules for union and intersection types (with one argument instantiated) are distinctly monad- and comonad- like, respectively. With some suggestive naming, we have
type Union X = X | B
join: Union (Union X) == Union X
pure: X <: (Union X)
type Intersect X = X & B
dup: Intersect X == Intersect (Intersect X)
extract: Intersect X <: X
These look like strictified versions of (co)monads, and satisfy analogues of the (co)monad laws, except they aren't endofunctors (bind is the closest we can get to map and afaict has to be implemented separately).
Is this just a cute coincidence or is there something deeper going on?