Repository navigation
the types 'T' and 'typeof Class' have no overlapΒ #44645
Description
Activity
- addedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
on Jun 18, 2021 RyanCavanaugh commented
on Jun 18, 2021 MemberMore actionsNot all comparisons are allowed; you can upcast either side to
unknownif this was intentional.Thanks for replying.
I'm reducing it from my use cases. but it seems I reduced it too much without knowing it's intentional workclass Class { } class Class2 extends Class { dummy = 0; } class Class3 { } function test<T extends typeof Class>(a:T):void{ if (a === Class) {} // it's okay if (a === Class3) {} // it's okay if (a === Class2) {} // it has problem } const test2:typeof Class = Class2; // it's okay
on this case. it has the same problem.
I thought this should be possible. but it also occurred in overall versions.- addedBugA bug in TypeScriptA bug in TypeScriptand removedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
on Jun 21, 2021 RyanCavanaugh commented
on Jun 21, 2021 MemberMore actionsThat's sort of weird
I've noticed another similar scenario where TS incorrectly asserts two types have no overlap and complains about their comparison:
class Foo<T extends true> { declare t: T hasKind<kind extends true> (kind: kind) { // This comparison appears to be unintentional because the types 'T' and 'kind' have no overlap. return this.t === kind } }
Amusingly in this case,
this.tandkindare guaranteed to be reference equal.Various manifestations of this error come up fairly often in my experience with generic parameters. This feels like the kind of message where TS should err on that side of caution, as it's not assignment- it's the language going out of its way to say "hey, this should never be possible, double check what you've done," which should really only be happening when there is certainty that the two types being compared are disjoint.
RyanCavanaugh commented
on Apr 20, 2023 MemberMore actionsTS should err on that side of caution
Isn't that what's happening, though?
TS should not prompt a developer to double check their logic based on a comparison between two values unless their types form a disjoint.
In the example I've highlighted, the two values are guaranteed to be equal based on their types, yet TS complains they have no overlap.
The more general case is if the parameters are unconstrained, i.e. TS has no information about their relationship to one another, you get the same message:
class Foo<T> { declare t: T hasKind<kind>(kind: kind) { // This comparison appears to be unintentional because the types 'T' and 'kind' have no overlap. return this.t === kind } }
Two
unknownvalues should certainly be comparable.RyanCavanaugh commented
on Apr 20, 2023 MemberMore actionsI don't know what to say except that this is super, super intentional, and you really should get warned here. These are the kinds of checks where when we tighten them even slightly, we find huge numbers of actual bugs in real code.
There are all kinds of mistakes you can make with
===which are not provably always-false but very unlikely to be intentional. Issuing a small number of false positives in weird code to get true positives in bad code is the trade-off that all typecheckers make on purpose.But in the example I mentioned, there is absolutely no reason to believe that comparison is unintentional.
Comparing two values of type
unknownis of course legal. This scenario is completely equivalent from TS's perspective based on this context. You can constrain the generics however you want, e.g. both tonumber. Same result- TS won't let you compare the two numbers for equality.I know often the
===warnings are useful and I'm not suggesting that the majority of them are wrong or unhelpful- usually when TS claims the operands have no overlap, it's because they don't.That said, there is something that occurs when comparing two generics like this that results in TS making an overtly false claim that it has no evidence to make- i.e. that those types have no overlap.
The only time this error should happen when comparing two generics like these are when both are constrained and the types of the two constraints form a disjoint. Other than that, it's both factually and practically wrong to assume the comparison is unintentional.
I originally encountered this while writing a very uninteresting snippet of code to check if a Node type had a certain constraint kind, represented as a string. Despite both generics being constrained to the exact same type (in this case, the union
"domain" | "class" | "value"), TS wouldn't allow me to compare them.- addedDomain: check: Control FlowThe issue relates to control flow analysisThe issue relates to control flow analysis
on Oct 16, 2025
Bug Report
π Search Terms
template class no overlap label:Bug
π Version & Regression Information
4.3.4 / 4.4.0-dev.20210617 / Nightly Playground
β― Playground Link
Playground Link
π» Code
π Actual behavior
ts2367 error.
acan beClassπ Expected behavior
no error.
acan beClass