Conditional type inside function resolves differently than at top-level
See original GitHub issueBug Report
🔎 Search Terms
regression conditional type inside function behaves difference
🕗 Version & Regression Information
- This changed between versions 4.2.3 and 4.3.5
⏯ Playground Link
💻 Code
{
type A = Record<string, number>
type B = Record<'a' | 'b', number>
const x: A extends B ? true : false = false; // ok
}
function test() {
type A = Record<string, number>
type B = Record<'a' | 'b', number>
const x: A extends B ? true : false = false; // error
}
🙁 Actual behavior
The conditional type resolves differently in global vs local scope.
🙂 Expected behavior
Both should resolve the same way, preferably false
in both cases.
Additional Details
This seems to have something to do with the way typescript compares aliases, wrapping one of the Record
types in Omit<Record<...>, never>
causes the comparison to behave normally
function test() {
type A = Record<string, number>
type B = Record<'a' | 'b', number>
const x: A extends B ? true : false = false; // error
}
function test2() {
type A = Omit<Record<string, number>, never>
type B = Record<'a' | 'b', number>
const x: A extends B ? true : false = false; // ok
}
function test3() {
type A = Record<string, number>;
type B = Omit<Record<'a' | 'b', number>, never>
const x: A extends B ? true : false = false; // ok
}
function test4() {
type A = Omit<Record<string, number>, never>;
type B = Omit<Record<'a' | 'b', number>, never>
const x: A extends B ? true : false = false; // error
}
Issue Analytics
- State:
- Created a year ago
- Reactions:6
- Comments:6 (3 by maintainers)
Top Results From Across the Web
Documentation - TypeScript 2.8
A conditional type T extends U ? X : Y is either resolved to X or Y , or deferred because the condition...
Read more >Resolvers - Apollo GraphQL Docs
The resolver map has top-level fields that correspond to your schema's types (such as Query above). Each resolver function belongs to whichever type...
Read more >Conditional result is incorrect when providing generics ...
Resolving of conditional types involving unbound generic type arguments is deferred. At that point the compiler doesn't know what ...
Read more >Why does a Typescript type conditional on `T extends ...
When T extends undefined is false, T appears to turns into never in the else branch, but only inside a function parameter list......
Read more >React conditional rendering: 9 methods with examples
Conditional rendering refers to delivering elements & components based on certain conditions. Learn how to do conditional rendering in ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Wow… it feels so wrong that an undocumented internal implementation detail like that should affect assignability. Not that that doesn’t happen elsewhere (variance measurement being what it is), but this one is particularly hard to come up with theoretical justification for without popping the hood of the compiler.
No worries, I understand it’s a design limitation; it’s not really the unsoundness that bothers me but moreso that I’m trying to figure out the rationale for the discrepency below so I can try to invent a theoretical explanation for it that doesn’t involve popping the hood 😉
edit: I just realized this probably only affects the case where you’re creating type aliases for generic instantiations, and things directly typed as
Record
s (or whatever else) will relate more consistently (i.e. always variance-based). That’s not so bad, in that case.