1

I have a conditional type where both sides of the condition are identical:

type Wut<T> = T extends number ? string | T : string | T

(This is not very useful. I'm just trying to understand what's going on.)

I can use the type as expected:

const huh1: Wut<number> = 'huh'  // OK
const huh2: Wut<object> = 'huh'  // OK
const huh3: Wut<string> = 'huh'  // OK
const huh4: Wut<number> = 22     // OK

... until I try to inherit from other generics:

function hmmm<N extends number, S extends string>() {
    const huh1: Wut<N> = 'huh' // <- Type 'string' is not assignable to 'Wut<T>'
    const huh2: Wut<N> = 22    // <- Type 'number' is not assignable to 'Wut<T>'
    const huh3: Wut<S> = 'huh' // <- Type 'string' is not assignable to 'Wut<T>'
}

See Typescript playground.

What's wrong with my conditional type here?

Sasgorilla
  • 2,403
  • 2
  • 29
  • 56
  • I'm not exactly sure *why* it's erroring, but [disabling distribution](https://tsplay.dev/N73KPN) does solve it. – kelsny Mar 29 '23 at 18:09
  • Ah, I know now. If you pass `never`, the result is `never`, and nothing is assignable to `never`! – kelsny Mar 29 '23 at 18:11
  • `N extends number` actually means that it's a more specific form of number. For example, it could be `1 | 2`. With this, 22 wouldn't be a valid number. Same thing goes for `S extends string`. I don't know why `huh1` isn't valid though. – ShamPooSham Mar 29 '23 at 18:23

1 Answers1

2

There's an error here because calls like hmmm<never, never>() are valid, and Wut<never> is reduced to never. See this related post for why it produces never. Since nothing is assignable to never, you get an error. You can fix this by disabling distribution in the conditional:

type Wut<T> = [T] extends [object] ? string | ((x: T) => number) : string | ((x: T) => number)

Now, [never] extends [object] won't distribute, so you'll get string | ((x: never) => number), not never.

Playground

kelsny
  • 23,009
  • 3
  • 19
  • 48