Skip to content
Advertisement

Using union type as function parameter

I have a type defined like so:

type FieldToAction = {
            [key in ApiActions]: ((field: Field) => void) | ((field: Field, fieldValue: FieldValue) => void)
        }

where FieldValue is a union of types:

type FieldValue = string | string[] | AssigneeValue | PriorityValue

I have a variable object where I then declare the functions set by the above types:

const fieldToAction: FieldToAction = {
            .
            .
            .
            "SET_DESCRIPTION": (field: Field, fieldValue: string) => field.setDescription(fieldValue),
            "SET_LABELS_VALUE": (field: Field, fieldValue: string[]) => field.setValue(fieldValue)
        };

This produces an error where the values in the object are not of type FieldToAction, I kind of understand why since I am now constraining the parameter to be a string or string[].

My question is: Is there a way of still using the union of types’ type and constraining the value in the parameter?

Thank you

Advertisement

Answer

Instead of using union | you should use intersection &. Intersection of functions produces a function overloading.

type FieldToAction = {
    [key in ApiActions]: ((field: Field) => void) & ((field: Field, fieldValue: FieldValue) => void)
}

For instance, imagine you have this:

type A = (a: string) => void
type B = (b: number) => void

type Union = A | B


declare const fn: Union

fn() // fn expects `never`

fn expects never because TS is trying to find most common type, which will conform each function in a union. To find such common type, TS intersects function arguments. It means that fn expects string & number, which in turn evaluates to never. See this legendary answer.

Let’s try this:

type A = (a: string) => void
type B = (b: 'a') => void

type Union = A | B

declare const fn: Union

fn() // expects "a"

Now, fn expects "a" because it is safe to provide this to both functions. string & "a" === "a".

This is why you almost never want to end up with union of functions.

Advertisement