-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Type parameters in custom type guards don't seem to have the same meaning as in their predicates #4212
Comments
@Aleksey-Bykov notice that you are using a type parameter And at the else clause you are subtracting the type |
why does the if I understood your right how function isNonVoid<a>(value: void | a) : <b>(value is b) {
return undefined;
} but that is at very least surprising that the knowledge about what |
@tinganho Please notice that this is not the first time when people sees guard expressions as working in unexpected way. Please search for all issues (open and closed) and you see that something is wrong with them. Either this construct in not natural to people or the people that have problem should not use TS as they are not target group. |
@Aleksey-Bykov Sorry, after looking at it more closely it probably is a bug. |
I just noticed that type parameter matching for union types does not work on the following case too: function f<T>(x: string | T): T {
return undefined;
}
let a: string | number;
let b = f(a); // b: string | number, while it should be number? |
Was there any luck figuring out whether it is a bug or was done by design? |
Seems like a bug if the type predicate is intended to work the same as other type guard forms. That is, if you apply this logic (from 4.24 in the spec):
it seems like the two cases in the original post should work as you expected and not how they are at the moment. |
@danquirk If this is a bug then probably my above comment is also? function f<T>(x: string | T): T {
return undefined;
}
let a: string | number;
let b = f(a); // b: string | number, while it should be number? TS doesn't seem to remove matched types before the type parameter is decided. Though I would argue that if you have more than 1 type parameter it would be very hard to decide which type the type parameter should have. function f<T, U>(x: string | T | U): T {
return undefined;
}
let a: string | number | boolean;
let b = f(a); // what should type of b be? |
It's not clear whether that's really desirable. For instance: |
if I were you I would have banned unions with more than one bare type parameter i mean from practical stand point |
I'm not sure whether this is desirable or not to have the functionality in my previous comment. Though my point is that my described problem is the same as OP? function baz<a>(value: void | a): void {
if (isNonVoid(value)) {
// value is void | a
} else {
// value is {}
}
} Notice the parameter type for |
I think situations like in unions with more than one type parameter regardless of the context should end up with a compilation error |
@ahejlsberg, there seems to be an unresolved question related to how TypeScript is designed, would you please take a look? |
@vladima points out that this is not related to type guards, but the way that unions are inferred. In the example below,
declare function removeString<T>(a: T | string): T;
function bar<U>(b: U | string): U {
return removeString(b);
} @ahejlsberg, can you take a look at this? You made a previous fix in #1035 to fix #1011, but I think this issue is more complex than that one. Is this worth it for us to fix? There are some related issues that might have the same root cause. I'll add references to this issue if I find any. |
|
@Aleksey-Bykov, @ahejlsberg's answer on issue #2264 that you filed in March is basically: "we do not "carve up" [aka destructure, ed] a union type ... but proposals are certainly welcome". |
got it, will be looking hard into it |
Now fixed by #5738. |
I know I am not supposed to use values of
void
, because one day they might be banned. But for time being I don't understand is it by design or by mistake that theisVoid
guard works whereasisNonVoid
doesn't in the example below:How come that seemingly identical guard implementation breaks apart entirely?
The text was updated successfully, but these errors were encountered: