Open ozyman42 opened 3 years ago
Shorter repro. It's not obvious to me which of these is the "correct" answer given the definitions, but I agree a difference is unexpected.
type X<T, U> = { traits: T & U };
// XX: true
type XX = X<true, true> extends X<any, false> ? false : true;
// Same as above, but with & {} at the end
type Y<T, U> = { traits: T & U } & {};
// YY: false
type YY = Y<true, true> extends Y<any, false> ? false : true;
Variance measurement. We only do alias symbol variance measurement for object and conditional types. So X
has variance measurement applied, while Y
does not. The variance is being measured as both parameters being strictly Covariant
, however any
in an intersection mucks it up (by acting like both the bottom and top type) - {traits: false & any}
is {traits: any}
, which {traits: true}
definitely extends, hence the structural result in YY
.
I'm curious, why is false & any
equal to any
in the first place? I had figured any
is the set of all types and so the intersection of any
and false
should be false
.
You want unknown
- any
is actually the "disable the type checker for this element, it's untyped, so taint anything it touches as also untyped" type.
Bug Report
🔎 Search Terms
🕗 Version & Regression Information
Confirmed that this issue appears in TypeScript versions 3.7, 4.1, 4.2
⏯ Playground Link
Playground link with relevant code
💻 Code
Notice that the types
t1
,t2
,t3
,t4
all evaluate to true. Right away it should raise alarms thatt4
is evaluated totrue
because I thought that whenever we intersect a concrete type withany
, it is still consideredany
by the TS compiler even if that behavior itself is an odd choice. Now things get stranger if we change the definition ofContainer
toNotice that I intersected on a
{}
type at the end.🙁 Actual behavior
t4
now evaluates tofalse
. This definitely has something to do with thetraits
being a intersect type and theContainer
taking anany
as type parameter, because if we replace theany
withIsA
orA
when instantiating theContainer
in the extends clause then all evaluate to true again regardless of whetherContainer
has an intersection with{}
or not.🙂 Expected behavior
Intersecting an empty object type
{}
withContainer
should not have changed the evaluation of the conditional type.t4
should either evaluate totrue
orfalse
in both scenarios. Probablyfalse
since it seems a concrete type intersected withany
is stillany
. If TS worked as I would ideally have it thentype thing = 0 & any
would evaluate to0
in which caset4
should betrue
in both cases actually, but TS saystype thing = 0 & any
is equivalent toany
sot4
should always befalse
.