Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't this conditional with generic keyof be eagerly resolved?

Tags:

typescript

function broken<T>(value: T) {
  type Test = keyof T extends keyof T ? 1 : 0
}

Why can't Test in the example above be eagerly resolved to 1? There's something I don't understand about the compiler that should answer this question for me.

Interestingly enough, there is a workaround:

function workaround<T>(value: T) {
  type Test = [keyof T] extends [keyof T] ? 1 : 0
}

Playground here

like image 830
aleclarson Avatar asked Sep 05 '25 02:09

aleclarson


1 Answers

The answer to the question probably involves a bug fix introduced in TypeScript 3.3. The description of the new way of evaluating conditional types is:

For a conditional type T extends U ? X : Y, the algorithm we use to determine whether to defer resolution of a conditional type is:

  • we resolve to Y when T is not assignable to U considering all type parameters referenced in T and U related (i.e. T is definitely not assignable to U),
  • otherwise we resolve to X when T is assignable to U considering all type parameters referenced in T and U unrelated (i.e. T is definitely assignable to U),
  • otherwise we defer resolution.

So it looks like keyof T extends keyof T ? 1 : 0 is deferred, because keyof T1 is not assignable to keyof T2 when T1 and T2 are unrelated types. This deferral isn't exactly wrong, but it does seem like a limitation.

Indeed if I try your code in TS 3.2.1 it is eagerly resolved, so this was a change introduced for TS3.3.

Curiously my reading of that bug fix's algorithm description looks like it should apply to your workaround also. I'm not sure why [keyof T] extends [keyof T] would change things, since [keyof T1] isn't definitely assignable to [keyof T2], if T1 and T2 are unrelated. So some mystery still remains here. Haven't been able to crack it yet, so I'll probably just give up now. Oh well!


It also looks like someone reported this exact issue where X extends X ? 1 : 0 is not eagerly resolved (and they also noticed that wrapping in a one-tuple "fixes" it), and the issue was tagged as a bug, so maybe it will be addressed?


Okay, hope that helps; good luck!

like image 140
jcalz Avatar answered Sep 07 '25 23:09

jcalz