Agreement is found in the belief that, regardless of the value of T
, Foo<T>
should be capable of being assigned to
T extends string ? string | Foo<T> : Foo<T>
. This concept may seem complex to confirm because if
T
represents a
union type (for example,
number | Date
), then
Foo<T>
will not be a union type (such as
Foo<number | Date>
), but
T extends string ? string | Foo<T> : Foo<T>
will become a new union type (like
Foo<number> | Foo<Date>
). This behavior occurs due to
T extends string ? ... : ...
functioning as a
distributive conditional type that disassembles unions prior to evaluation and recombines them afterward. Hence, the assignability of the conditional type to
Foo<T>
under any conditions related to
T
relies on the specific definition of
Foo<T>
and its covariant relationship with
T
(refer to this Q/A for an explanation on variance).
Despite these valid points, why doesn't the compiler acknowledge this?
Primarily, when considering conditional types involving generic type parameters, the compiler opts to postpone their evaluation. While efforts were made within microsoft/TypeScript#46429 to enable a type to be assignable to a conditional type under certain circumstances, it mainly applies to non-distributive types devoid of the infer
keyword. Unfortunately, since you are working with a distributive type, this approach does not function here.
Consequently, the assessment of
T extends string ? string | Foo<T> : Foo<T>
remains pending until a specific value is attributed to
T
. As long as
T
remains unspecified within the confines of
bar()
, the conditional type goes unevaluated, mask-like from the perspective of the compiler, thus rendering it impossible to verify assignability unless the designated value conforms precisely to the conditional type. Regrettably,
Foo<T>
fails to meet these requirements, leading to error notifications by the compiler.
Explore code on Playground