Repository navigation
Closed
Labels
Design LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixed
Description
Bug Report
I apologize for the name of issue, I was not able to correctly formulate the problem.
🔎 Search Terms
4.2, regression, class, extends, union
🕗 Version & Regression Information
This changed between versions 4.1.5 and 4.2.2
(if we take dev then between versions 4.2.0-dev.20210209 and 4.2.0-insiders.20210210)
⏯ Playground Link
Playground link with relevant code
💻 Code
I apologize again, I have shortened the example as much as I can.
/** some declared types */
declare abstract class GlobalController<P, S, SS> {
isLocal: false;
abstract getProps(storeState: SS, props: P, state: S): void;
}
declare abstract class LocalController<P, S> {
isLocal: true;
abstract getProps(props: P, state: S): void;
}
interface GlobalControllerClass<P, S, SS> {
new(): GlobalController<P, S, SS>;
}
interface LocalControllerClass<P, S> {
new(): LocalController<P, S>;
}
type ControllerClass<P, S, SS = {}> = GlobalControllerClass<P, S, SS> | LocalControllerClass<P, S>;
declare const createEnhancer: <P, S, SS = void>(Wrapper: ControllerClass<P, S, SS>) => any;
/** usage */
type ControllerState = {
bar: any
};
type ControllerProps = {
baz: any
};
/** fall since TS4.2 (4.1- works fine) */
class FailWithTS42 extends LocalController<ControllerProps, ControllerState> {
getProps(props: ControllerProps, state: ControllerState) {}
}
createEnhancer(FailWithTS42);in the sandbox above the same code plus some workarounds that might suggest something
🙁 Actual behavior
createEnhancer(FailWithTS42) in the last line shows the error:
Argument of type 'typeof FailWithTS42' is not assignable to parameter of type 'ControllerClass<ControllerState, ControllerState, ControllerProps>'.
Type 'typeof FailWithTS42' is not assignable to type 'GlobalControllerClass<ControllerState, ControllerState, ControllerProps>'.
Construct signature return types 'FailWithTS42' and 'GlobalController<ControllerState, ControllerState, ControllerProps>' are incompatible.
The types of 'isLocal' are incompatible between these types.
Type 'true' is not assignable to type 'false'.
🙂 Expected behavior
I can call createEnhancer with class FailWithTS42
Metadata
Metadata
Assignees
Labels
Design LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixed
Activity
[-]Some regression with union of classes[/-][+]Some regression with union of classes in TS4.2[/+]RyanCavanaugh commentedon Apr 21, 2021
Here's a reduced version
The TL:DR is that we're getting tripped up here and collecting inferences from
GlobalControllerfrom theaandbparameters. What should be happening is that we'd detect thatLocalController & GlobalControllerisneverso there shouldn't be any inference candidates collected from the latter type.I don't know why this ever worked.
RyanCavanaugh commentedon Apr 21, 2021
cc Anders Hejlsberg (@ahejlsberg) for possible interest
dartess commentedon Jul 2, 2021
Wesley Wigham (@weswigham) hi! thank you for your work!
i tried version
npm:@typescript-deploys/[email protected].The short version of the code from Ryan Cavanaugh (@RyanCavanaugh) now really works without errors. But the original code still doesn't work. I tried to shorten my code a little more so that the error persists:
9 remaining items
RyanCavanaugh commentedon Feb 15, 2023
Looking at this again, something is just going wrong in a bad way, I don't think this is some "subtle" thing without a direct fix, unless I'm really missing something. Trimming the repro down more and poking at the adjacent cases which do work:
That said we haven't seen other reports of this so I think this needs to be deprioritized in terms of scheduled work.
Mateusz Burzyński (@Andarist) this seems very much up your alley in terms of investigations?
Andarist commentedon Feb 15, 2023
RyanCavanaugh commentedon Feb 15, 2023
Me last night, going to bed right after posting that comment

I take back 90% of it; the problem is obviously that we're doing
X<T> | Y<->X<U>candidate collection via type identity in the first two cases (which works fine), but structural inference in the last case (which doesn't check discriminants and thus fails). This is indeed going to be difficult.Andarist commentedon Feb 15, 2023
is there a specific reason why structural inference doesn't check discriminates or why this worked pre-4.2? 🤔
RyanCavanaugh commentedon Feb 15, 2023
I suspect this only worked by accident in 4.1-.
As for why to not check for discriminants - 40% perf hit to material-ui (I remember this one)
#43853 (comment)