-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Custom type guard function #3262
Conversation
@@ -429,6 +431,9 @@ module ts { | |||
case SyntaxKind.TypeParameter: | |||
bindDeclaration(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes, /*isBlockScopeContainer*/ false); | |||
break; | |||
case SyntaxKind.TypeGuardType: | |||
bindDeclaration(<Declaration>node, (SymbolFlags.TypeGuardType | SymbolFlags.Value), SymbolFlags.TypeGuardTypeExcludes, /*isBlockScopeContainer*/ false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why SymbolFlags.Value
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is that even bound? it does not create a symbol.. it is not creating a new type, it is just boolean
with additional properties.. correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the binding on a later commit.
pinging @JsonFreeman and @ahejlsberg for this one as well. |
@tinganho thanks for submitting this change. I took a first stab at reviewing it. Overall i do not have major concerns, just my comments above. i would want @JsonFreeman and/or @ahejlsberg to take a look as well though. |
I haven't started reviewing this yet, but I don't think it's possible to only allow a certain type kind in return position because of type argument inference. You could have a function like this function moveReturnToParameter<T>(func: () => T): (p: T) => void; and then passing in a type guarding function would output a function that takes a type guard as a parameter. |
Also a function that takes a type guard type(not a type guard function) as a parameter is pretty much useless. Let say that that the returned function is: function(isFoo: item is Foo) {
if(isFoo) {// This won't be able to take an argument so it is not useful?
}
} Maybe have the type checker catch all type guard types so that they are only assigned to function like declarations? |
a65d0c3
to
96a17fa
Compare
Actually, I take that back. It is possible if you special case inference to infer boolean every time it encounters one of these type guards. |
@JsonFreeman just for clarification do you mean that: function moveReturnToParameter<T>(func: () => T): (p: T) => void; will convert the returned function to accept a boolean instead of a type guard type? And so every non-function declaration with a declared type guard type will be converted to boolean? |
@mhegazy I fixed some of the issue you pointed out. Though I didn't understood some of your comments, it would be good if you could clarify some of them. |
|
||
export interface TypeGuardType extends Type { | ||
parameterName: string; | ||
parameterIndex?: number; // Call expression argument |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the parameterName is a name found in a binding pattern, will parameterIndex be the index of the top level binding pattern? How will you then know which binding element needs to be narrowed? Also, please ensure you have tests that try to type guard a parameter inside a binding pattern.
8da7db9
to
487dff5
Compare
I just added a restriction on type predicate signature declarations. Constructors, get/set accessors can't have type predicates. I also fixed some of the feedback. |
Just added an error for referencing a top-level binding element. Also addressed all the other feedback. |
4a14e61
to
67f9ab0
Compare
b34449f
to
53b934c
Compare
53b934c
to
51a43dd
Compare
Thanks @tinganho! After these last few minor tweaks, can you merge the upstream master branch into here? Then we can work on merging this in. |
Let me know if I miss anything here, but wonder what happens in the following example? function isB(b: any): x is B {...} I would assume we will give an error in this case.Also could you add the case in the tests. |
@@ -8486,6 +8587,34 @@ module ts { | |||
node.kind === SyntaxKind.FunctionExpression; | |||
} | |||
|
|||
function getTypePredicateParameterIndex(parameterList: NodeArray<ParameterDeclaration>, parameter: Identifier): number { | |||
let index = -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is index used?
Yes @yuit, that code would be an error. The function |
@JsonFreeman. I see, Thanks :) |
Awesome job @tinganho! Thank you for implementing this much requested feature! |
Really cool to see this feature go in. Great work! 🏆 |
thanks @JsonFreeman @RyanCavanaugh . 😃 |
I like this! thanks @tinganho |
@tinganho Nice work! |
prepares to re-write all the definition files Nice work @tinganho! |
Implements only the function part of #1007. I thought it was best to have some early feedback first before I implement the class method part. So that I know I'm on the same page.
I consider the type guard type as a new type. Pls. check my tests for all specifications right now. I'm not sure if it's according to your specs. So would be good to have feedback on that.
Another question I have is if I should ban declaring type guard types on non-function-like declarations? I haven't implemented this ban yet. Example: