You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Enhance Control‑Flow Narrowing for never‑returning Functions Passed as Parameters #62235
TypeScript currently narrows types when a function known at compile time (e.g., a throwError() declared with return type never) is invoked. However, when the thrower function is injected via a parameter - even if typed to return never - TS does not narrow, because it cannot assume that caller will always pass in a never function. This limitation forces developers into workarounds and undermines ergonomics for generic code patterns.
Code
functionthrowError(message: string): never{thrownewError(message);}functioncreatorFunction(fn: (data: unknown,error: typeofthrowError)=>Promise<any>){returnasync(data: unknown)=>awaitfn(data,throwError);}constgetUserName=creatorFunction(async(_,throwErrorFromInside)=>{// Simulating a user fetch operationconstuser=Math.random()<0.5 ? null : {name: "test"};if(!user)throwErrorFromInside("User not found");console.log(user.name);// ❌ TypeScript error: 'user' is possibly 'null'if(!user)throwError("User not found");console.log(user.name);// ✅ No error here});
Actual behavior
TypeScript does not narrow the user variable after throwErrorFromInside(...) is called, even though:
The parameter is typed as a never-returning function.
The control flow after the call should be unreachable if the condition is true.
The exact same code works when calling the throwError(...) function directly.
Expected behavior
TypeScript should treat:
if(!user)throwErrorFromInside(...);
as equivalent to:
if(!user)throwError(...);
and narrow user accordingly — i.e., allow user.name with no error afterward.
Technical Considerations / Trade-offs
No changes to emitted JS; strictly compile-time.
Minimal and safe extension to control-flow analysis.
Could reuse existing mechanisms for recognizing class/global functions, but would need enhancements to support parameter references where the function is known to return never.
Backward Compatibility
No breaking changes; only narrowing behavior is enhanced for specific patterns.
Conclusion
The ask is modest but meaningful: allow TypeScript to narrow after calls to never-typed function parameters when safe. This eliminates common developer frustrations without runtime impact.
Maybe, but currently there is no work around. Suppose throwErrorFromInside needs to be generic and inherit types from the creatorFunction. How can i achieve this?
Activity
MartinJohns commentedon Aug 8, 2025
This is intentional and for performance reasons.
mattiamalonni commentedon Aug 8, 2025
Maybe, but currently there is no work around. Suppose
throwErrorFromInsideneeds to be generic and inherit types from thecreatorFunction. How can i achieve this?MartinJohns commentedon Aug 8, 2025
You can find the requirements here: #32695
Your case works if you explicitly type
throwErrorFromInside:throwErrorFromInside: (_: string) => nevermattiamalonni commentedon Aug 8, 2025
Right. Thats a good point.
2 more considerations:
typescript-bot commentedon Aug 11, 2025
This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.