Thank you for the helpful response and pointers. I think I need to take my time to sort this out, thanks a lot and I'll come back with a better understanding, hopefully!
I did my homework. Now I'm not so certain about everything, so please take this with a grain of salt.
Typescript's generic functions seem to act like they're contravariant over the type parameter's type bound. I'm not entirely sure though.
// Assignment succeeds with F<unknown> -> F<string>
// Assignment fails with F<string> -> F<unknown>
const a1: <T extends unknown>(x: T) => T = (x) => x;
const b1: <U extends string>(y: U) => U = a1;
const c1: typeof a1 = b1; // error
const a2: <T extends unknown>(x: T) => string = String;
const b2: <U extends string>(x: U) => string = a2;
const c2: typeof a2 = b2; // error
declare const a3: <T extends unknown>() => T;
const b3: <U extends string>() => U = a3;
const c3: typeof a3 = b3; // error
@masaeedu This seems like the {co,contra}variance of the types is independent to whether you can do a {co,contra}map on it. May I ask, did I mess up again, or is this another unsoundness, or is this the way it is? Anyhow thank you so much for the helpful discussion! heart
So "variance" is a property that type constructors have. Before we ask "is it co/contra variant", we should consider what type constructor we're asking the question about. A type constructor looks like this:
There's various ways one could extract type constructors from the examples given (i.e. of which the ascribed types are instantiations), but I think it would involve less guesswork if you gave it some thought and formulated it explicitly.