0

What's the difference between the following two conditional types:

type IfVoid<P, True, False> = [void] extends [P] ? True : False
type IfVoid<P, True, False> = void extends P ? True : False
jddxf
  • 1,850
  • 3
  • 12
  • 19
  • 1
    After testing a bunch of cases on https://typescript-play.js.org/ I can't seem to find any difference between them. Is there a more concrete case where you found this situation? – Badashi Dec 29 '20 at 13:45
  • The single element tuples is generally used to avoid the distributive property of conditional types, but `void` isn't a union so I don't think it does anything. – Aplet123 Dec 29 '20 at 13:54
  • Interestingly, I just stumbled upon another question that might be relevant; specifically, using tuples to avoid the distributive property of types => https://stackoverflow.com/questions/65492464/typescript-never-type-condition – Badashi Dec 29 '20 at 13:54

1 Answers1

4

Conditional types distribute over unions when there is a "naked type parameter" in the first part of an extends clause, such that T extends A ? B : C is equivalent to (T1 extends A ? B : C) | (T2 extends A ? B : C) when T is a union type like T1 | T2. So the following two types are, in general, not equivalent because the first one distributes when T is a union and the second one doesn't:

  • T extends A ? B : C
  • [T] extends [A] ? B : C

For a concrete example where they are different, see the example code below (Playground Link):

type Test1<T> = T extends 'foo' ? 'bar' : 'baz'
type Test2<T> = [T] extends ['foo'] ? 'bar' : 'baz'

type R1 = Test1<'foo' | 'bar'> // 'bar' | 'baz'
type R2 = Test2<'foo' | 'bar'> // 'baz'

For a practical example where it makes a difference, see this other Q&A.

However, in your case void is not a type parameter, so it does not appear that there is any difference. Perhaps the code used to be different, or it was adapted from another piece of code where distributivity did make a difference.

kaya3
  • 47,440
  • 4
  • 68
  • 97
  • 2
    I'm sure you know this already, but the answer as written doesn't quite make this clear: Conditional types do not distribute across arbitrary unions; it only distributes across unions when the type being checked is a "bare"/"naked" type parameter as in `type F = X extends A ? B : C`. When you try to expand that out to put the union directly in the conditional expression, it is no longer a bare type parameter and thus no longer distributive. In particular, `(S | T) extends A ? B : C` is [not equivalent](https://tsplay.dev/BmxvKw) to `(S extends A ? B : C) | (T extends A ? B : C)`. – jcalz Dec 29 '20 at 15:49
  • 1
    Here you have link to docs https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types – captain-yossarian from Ukraine Dec 29 '20 at 18:58
  • If you want to disable distributivity - just use square brackets - this is how I understand it. – captain-yossarian from Ukraine Dec 29 '20 at 18:59