TypeScript generic with conditional evaluates union types separately

I am trying to create a TypeScript type that will represent either a VoidFunction or a function with a single parameter based on a provided generic.

Using a conditional, the type looks like this:

type VoidFunctionOrWithParams<Params> = Params extends void
    ? VoidFunction
    : (params: Params) => void;

An example usage might look like this:

type WithStringParams = VoidFunctionOrWithParams<'one' | 'two'>;

Expected Result Type

(params: 'one' | 'two') => void

Actual Result Type

((params: "one") => void) | ((params: "two") => void)

Why does TypeScript interpret this as two separate functions with no overlap? Is there a way around this? What I really want is one function type where params could be any of the values in the union – not different function types.

>Solution :

You are seeing the effects of conditional distributive types here. To avoid distribution, you can wrap the generic type in a tuple.

type VoidFunctionOrWithParams<Params> = [Params] extends [void]
    ? VoidFunction
    : (params: Params) => void;

type WithStringParams = VoidFunctionOrWithParams<'one' | 'two'>;
// type WithStringParams = (params: "one" | "two") => void

Playground

Leave a Reply