classFoo<T>{constructor(publicinner: T){}}classBarClass<T>{constructor(publicaccessor: (state: T)=>boolean){}}{// This is my actual production use case, narrowed down.// `bars` is an array of class instances with a generic inferred from// context of previous function calls.classContainer<C,F>{constructor(publicctx: C,publicfooFactory: (ctx: C)=>F,publicbars: BarClass<F>[],){}}constcontainer=newContainer(42,ctx=>newFoo({answer: ctx}),[newBarClass(state=>true)],// ^?// state is unknown)}{// The problem exists with a singular instance of the class however.classContainer<C,F>{constructor(publicctx: C,publicfooFactory: (ctx: C)=>F,publicbar: BarClass<F>,){}}constcontainerWithoutAnnotation=newContainer(42,ctx=>newFoo({answer: ctx}),newBarClass(state=>true),// ^?// state is unknown)constcontainerWithAnnotation=newContainer(42,(ctx: number)=>newFoo({answer: ctx}),// an explicit type annotation on ctx here fixes the issuenewBarClass(state=>true),// in all cases, but isn't practical for my API use case// ^?// state is Foo<{ answer: number }>)}{// Having a factory function with no arguments doesn't helpclassContainer<C,F>{constructor(publicctx: C,publicfooFactory: (ctx: C)=>F,publicbarFactory: ()=>BarClass<F>,){}}constcontainer=newContainer(42,ctx=>newFoo({answer: ctx}),()=>newBarClass(state=>true),// ^?// state is unknown)}{// A factory function with a dummy argument _does_ workclassContainer<C,F>{constructor(publicctx: C,publicfooFactory: (ctx: C)=>F,publicbarFactory: (dummy: never)=>BarClass<F>,){}}constcontainerWithDummy=newContainer(42,ctx=>newFoo({answer: ctx}),dummy=>newBarClass(state=>true),// ^?// state is Foo<{ answer: number }>)// however if the dummy argument isn't passed, it doesn't workconstcontainerWithWrongArity=newContainer(42,ctx=>newFoo({answer: ctx}),()=>newBarClass(state=>true),// ^?// state is unknown)}{typeBarObject<T>={accessor: (state: T)=>boolean}// A regular object is inferred correctly.classContainer<C,F>{constructor(publicctx: C,publicfooFactory: (ctx: C)=>F,publicbar: BarObject<F>,){}}constcontainer=newContainer(42,ctx=>newFoo({answer: ctx}),{accessor: state=>true},// ^?// state is Foo<{ answer: number }>)}The BarClass type isn't inferred correctly.
I think I'd expect BarClass to be inferred in all those cases? Except perhaps when the dummy argument is in the function signature, but the passed function has the wrong arity.
🔎 Search Terms
"intra expression inference class", "context sensitive class inference"
🕗 Version & Regression Information
⏯ Playground Link
https://www.typescriptlang.org/play/?#code/MYGwhgzhAEBiD28A8AVAfNA3gWAFDWmHgDsIAXAJwFdgz4KAKAByoCMQBLYaD44gUwoAuaCgCUWAL55puPKEgwAQmAoBhcFFQYc+QiXLVa9Zm07cwwYPyj0RDcmDL8R46AF4MrRCH5hiEpiysni6BAD04aIAFhwwcdAAtgCe0JZkVGAg0EwU8AAmNGQcJNBUEPyEkPwANNDEqnkA7vz50PnwTcQAdHgRUQAGrKoQAzww-mkUFGCp8ABmhJrxpGT+1jBNHGTRadAA5vwCFFw8xPOCFK3Q83mJfdCR+sTOAB5k0As5VwBuJeU3KjEWglYhVEAgCC9PQKKDQNQkNa8QRINR1WA6B4EIirIx0RhYgg5MynWivERowkEFjsU7zRCwdL0ZL2MkUiSeOA1KnE2ncYYUCAiFTqZZIDEAbQAuty9ARArICCEYQYPjikccPPV+E14YiwMiCXLoAAWABMsqJhDIrw8GAEuoQ8AYmDSpBawmttskYktRIlDugIo0igca2cduglCo-DEMsJTytSYIAD0APwJqKOCMJIEAa2InWIDzEMjwoQeTxQ0UquXg7H4iWg-FecTIm22uzA0AgvH2VHAFDOjmBlS+O0qsJg0U6-B+gmh2OWepeBuOqPRmONOMMRRMPJp5i9FL9VsPdIZTIoLOgDDZ8I5GFgp6J5-5qmFqhDWgxL4VD2VbFVWeDVBAAdU7eAqDIABBPh4HDUEtUDBFV0NBhCXNF8yUjQMnRdN0IA9EQcJ9F9A2DZYwycSpOWjWMX0TZMiXTTMe3DSpc2IAsixLcsVVWEC13Azs4MLRDSncbVdVQ0CjStLDCTvG0RGIKhElYQRH2kuBEAI-wiMEEibWgMjHiiSYWyYcxtijZImEqfxxKcJDShwmsrhuDhXhsKMa3GCAYzONIISqCoIDqVhoPGYgAHIPlydIuCyG56CSVIYIABQASTKCowv4QkKK-Kjs1ojB6N9NjmJYjNjSeMrxl05BXQM4j6nUzSh0kNA+NwZUwnM6AAAkwD+Yh9j2eYr1SeYgRBUoth2ep4CmftEiOdt2ngGw4o+GsQCYB4pxXOSNzgLcrR3aNjHkpM32PeEX2pEluHpeBGVum9lPJB9I2fA9XugAVPvxb7tMoxRxTQP8pAA-igME9VhKHKSUP1dDMItQkcM5PC9Na90jK9UyquNBhtOK0VQ0aujqAY6qauY1j6qzDimvzQsuj6gbKyiGCbhmwFgWKRbOz2QpEhSNb1M26AAH0OhseXoCaeg82O5dZJR86MSwHHVTxfdjRevlHspE3eSPd7QeZVkVL+zkActh6QZm+xJZSVS5y0yNIZ-GHCX-PRAOecghMNCCdgAEXU6W0Z1U6UYw41FO3Ey8cT-DCcMz1SLJq1PdSTPdX9iBqIjOmYwLokmKZmqWatBr2YSJ0kBz9q1I0wRTN6vRSzkPQnhnFp5yHDhFgndo49SVR1rluI9pyRRWjqWylYgJe1YoDWBPD5HI87MC8gmmCTjIYudO1zHU+x9PbRL5r9KJvOTLIpTKcTsuK-KqN6Zr-o9dmZ1SbmzGiHNuJc2LP3Msg9BoXwckGVQAB5VgAArfgtBtBakGgQSwGwIB2FvGVVw2lvDwF8P4eGg9AECyuP2Qcnx0GYI+AkXgFxpjXCIJw2gIBkiLiWIoJOhpdaXSJNdI2d0zxA3vBbZMD0bbu1vLI7Szt5FAwFJ+CgqCMFYN-EHOGIcEZhzVBjTUCcZJmMECnBSd8roZ3tFnAmhF2r5xfK1KwNhCGelphVemplGJRCZo3WuYCcwwDbh3YmXcuq9x5kAA
💻 Code
🙁 Actual behavior
The BarClass type isn't inferred correctly.
🙂 Expected behavior
I think I'd expect BarClass to be inferred in all those cases? Except perhaps when the dummy argument is in the function signature, but the passed function has the wrong arity.
Additional information about the issue
Under the umbrella of #47599
This PR+comment feels close #54183 (review)