-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use control flow analysis for type guards #2388
Comments
This would be nice. We should probably have a single issue for "Use control flow analysis for type guards" to unify all the various permutations here. |
+1 for this feature. |
@RyanCavanaugh I've updated the issue title, as you suggested. Happy to discuss it here. |
+1 function foo(x: number | string) {
if (typeof x === 'string') { throw 'No strings attached';}
return x * 2;
} |
👍 I prefer writing code without using |
👍 |
👍 |
+1 It is a basic coding style. |
👍 this would be really awesome to have. +1 as well for the same with a throw. |
Right now I am using type coercion to avoid falling into a pyramid of doom, so +1. |
I've opened a PR at #6959. |
Just ran in to this issue today and had to wrap my code in an else (dirty). Would love to see this implemented! |
Is it within scope to make this feature also operate on type intersections? class A { a: string; }
class B { b: string; }
function fn(param: A & B)
{
if (param instanceof A)
return;
param.a; // Generate a type error here?
} |
@paul-go what's the intent of the code here? I would expect |
@RyanCavanaugh You can get an class AB extends A implements B {
b = 'b';
} Of course The same problem exists with interfaces, but then you can't use This also raises that |
@paul-go The code is not a type error, since Maybe it's dead code if you think you can never fail the |
@jods4 By "Generate a type error here?", I actually meant "Can we generate a type error here?" |
@RyanCavanaugh: This is going to be controversial, but I think you may be making an assumption that all usages of And not that we should be striving to appease the completeness gods, it also seems like a pretty gapping completeness hole :-) |
FWIW I don't have strong beliefs about constructors. In the example you have there, though, I don't understand why we would want to generate an error there. If something is |
We use |
@paul-go The point is that this is valid in TS: class Foo { bar: string }
var foo: Foo = { bar: "a" };
console.log(foo instanceof Foo); // false even though foo is a Foo according to the type system Thus in your example even when |
If you changed the |
Just |
I think @paul-go is using type intersections to model what are more accurately type unions, because he feels that type unions are too cumbersome to use properly. I don't think "modelling it incorrectly because the correct way is inconvenient" is a good use-case to support. |
@paul-go from your description I think that you don't use intersection types the way they are intended... And I have the impression that your request is twisting let's take your last example: // or is it A & B ??
function fn(param: A | B) {
} You have to decide if Accessing members of both in an unguarded way would be a bug if the object is sometimes a Accessing members behind a guard kind of implies that If you actually have let param: A & B;
param.a = 1; // ok
param.b = 2; // ok
let restricted = <A>param;
restricted.a = 3; // ok
restricted.b = 4; // type error, no b on A. (actually ok at runtime, though) |
Yes, I'm aware of how type guards work. But all of this is pointless banter as TS isn't going to support our unfortunately bizarre use case. |
@paul-go Reading between the lines here, it seems like you'd like possibly-present members of union types to show up in the completion list. We already have this functionality for JavaScript code and could think about moving it to TypeScript if that'd be useful. One caveat would be that obviously these maybe-present members wouldn't actually work without a type guard of some sort, but it seems like you're writing that code anyway (just later). As in JS, we could show those with a sort of 'warning' formatting connotation. Thoughts? |
@RyanCavanaugh Is what you're proposing similar to generating an implicit interface that is a supertype of all types in the union, with the non-common properties marked optional? |
@RyanCavanaugh By "wouldn't actually work", I'm assuming you mean "will emit a compiler error when used"? If that's the case, unless I'm misunderstanding, I'm not sure if it's helpful to display provably-faulty members (at least as far as TS is concerned) in a completion list. |
@RyanCavanaugh Doesn't seem like a high-priority to me, but would probably fall into the "nice to have" bucket to me. If the IntelliSense presentation is well-done: dimmed member (because it's not legal to use at this point) with the containing types on the right (to provide insight as to which guard is required) would give an interesting glance at the underlying types. Better than, say, a completely empty IntelliSense popup. |
This is actually why we don't display all the members from union types. We don't know what type you have, so until you find a way to tell us, we're going to have to give an error if you use any member that the other types don't have. That's basically the issue. For the record, there was a lot of discussion on the completion list scenario when we were first thinking of union types. Exploratory coding is really helpful, and keeping friction low to leverage the IDE to do so makes users happy. Check #5334 out for something similar. Maybe this could be part of that suggestion. But if this is something we'd like to see, let's open another issue since the conversation has moved into something orthogonal to the main suggestion here. |
There's room for debate on this question, but I have a feeling that showing the extra properties (even grayed out), and then erroring on them is a bad experience. Though I suppose an argument could be made for showing the properties in the list (along with the associated type), but refusing to auto-complete them, but I think this would also be odd. |
@ivogabe I just pushed some changes to the controlFlowTypes branch that break |
TS 1.4
Type guard fails to narrow the union type when returning early.
Unfortunately, I get the following compiler error:
Clearly, the compiler should know at this point that it can't possibly be dealing with a
string
, as that scenario has already been returned.The text was updated successfully, but these errors were encountered: