-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Conditional type evaluation of type aliases produces different result than their equivalent substitution #48070
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
Comments
Version/regression info: behavior changed between 4.2.0-dev.20210111 and 4.2.0-dev.20210112 |
Looks like #42284 may be the cause, and therefore this is possibly a duplicate of #42421, #44119 (and so maybe #29698 in turn?), etc. Those are listed as "working as intended" (although it seems more like "design limitation" to me, but π€·ββοΈ). Okay, that's enough amateur sleuthing for me. Hopefully it helps the real TS squad with their triage. π¦βπ΅οΈββοΈ |
@ahejlsberg mentioned yesterday he was looking into variance computation, and this seems relevant... |
Yeah, there's an issue here. When relating two signatures that were instantiated from the same origin we erase type parameters as they're known to be the same. Since erasure substitutes |
Not sure if this is a separate bug (happy to file it -- maybe @ahejlsberg can comment?) or just an even worse variation of this one.
Not only does going through the IsItNumber alias change the output, it somehow ends up with |
@ddurschlag I think this is because |
This seems right. Avoiding primitive types produces more sensible results:
I find this combination of sometimes-eager/sometimes-lazy type evaluation difficult to work with. Why is string&number not eagerly reduced in general? Why are some conditional types eagerly evaluated, and some lazily so? At this point, I want a VSCode plugin that shows what TS thinks of my code internally (e.g. which type expressions are eager, which are lazy, which prevent tail recursive evaluation of conditional types, which are having their type parameters erased...). Even worse, I might want the ability to turn off certain eager evaluation optimizations per-line :( |
@ddurschlag The difference is that the conditional type in |
I have opened a duplicate issue at #57062 that I am closing in favor of this issue. However, just for information, this is the code sample. It produces the same problem as above, but slightly differently. type A<T> = {a: T extends true[] ? true : false};
type B = A<true[]>; // {a: true}
type C = A<boolean[]>; // {a: false}
type D = A<true[]> extends C ? true : false; // `false`, which is correct
type E = A<true[]> extends A<boolean[]> ? true : false; // `true`, which is incorrect In that code, the following works around the problem: type A<in T> = {a: T extends true[] ? true : false}; Another workaround: type A<T> = {a: T extends true[] ? true : false} & {}; |
I encountered another instance of this issue: type Number_Or_Nil<T> =
T extends number ? number :
T extends [] ? [] : never
type T = number | number[]
// Evaluates to `never` as expected.
let b:
T extends number ? number :
T extends [] ? [] : never = 0
// Evaluates to `number`..?
let a: Number_Or_Nil<T> = 0 The logic behind evaluating the type expression to |
No, that's just a distributive conditional type, which depends on whether the |
Bug Report
π Search Terms
extends
π Version & Regression Information
v4.5.4
β― Playground Link
Playground link with relevant code
π» Code
π Actual behavior
For the result2 expression, the only difference from result1 is that result1 uses the type rather than the specific S<'s1'> ,But they returned a completely different result. Result1 return true,Result2 return false
π Expected behavior
type Result1 and type Result2 should return false
The text was updated successfully, but these errors were encountered: