Repository navigation
Generalize never type handling for control flow analysis based type guard #12825
Description
Activity
It would be a great way to control the flow.
For now, you may use
returnif your are inside a function.function throwError(): never { throw new Error(); } let foo: string | undefined; if (!foo) { throwError(); return: } foo; // foo is string
or use a check typeguard
function throwError(): never { throw new Error(); } // Inferred return type is T function check<T>(x: T | undefined) { return x || throwError(); } let foo: string | undefined; let foosafe = check(foo); // foosafe is string
Reacted by BlakeRelated: #8655
- addedIn DiscussionNot yet reached consensusNot yet reached consensusSuggestionAn idea for TypeScriptAn idea for TypeScript
on Dec 12, 2016 I'd like to echo my support for this. Currently to get control flow analysis to work correctly in our codebase (which make use of a framework requiring the use of an external throwError style method), we explicitly
throw ''; // See https://github.com/Microsoft/TypeScript/issues/12825in the following line.ADDENDUM:
I've just noted RyanCavanaugh's comment on a duplicate thread.
The recommended workaround is to write return throwError();
We'll use this workaround from now on. It appears to not interfere with the returned type. 👍
if (!foo) { return throwError(); }
I currently use
const guaranteedFoo = foo || throwError()to strip away undefined from stuff that I know should never beundefined.Reacted by Aluan HaddadParzh (org) (@parzh) Depends on what your value's type is. If the type is
{ foo: string } | undefined, you already know it's not0,false, or any of those other things. If you do indeed have a mixed type that could contain booleans and strings and a multitude of other things, you should do a more specific check:foo !== undefined || throwError().I got
Object is possibly 'undefined'error aftertry { ... } catch (e) { ...; process.exit(1) }in node.
I expected thatprocess.exit(1)behave likethrowfor type inference.For other people googling this, this issue was addressed in #14490. Basically it seems the issue is TS currently has separate passes for flow control and type assignment, and the former needs to run first for the latter to work, and there didn't seem to be any clean solutions that would also handle imported functions, etc....
So the current workaround is justreturn neverReturningFunction();, which won't alter the return type and lets flow control do its thing.Reacted by Finn Merlett, Fabio Colella and Adrián Montesinos GonzálezThe workaround doesn't work in top-level code outside functions, since there's no
returnthere.Ruslan Fadeev (@Kinrany) you can still use the other workaround
val !== undefined || throw new Error()The original code in this issue has been working as expected for a while. Is there anything else above that isn't right? I'm thinking no, and that this issue can be closed.
Reacted by Fabio Colella and Nathan Sarang-Walters
I guess there would be some duplicates, but I cannot find it.
TypeScript Version: 2.1.14
Code