1

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

1
  • Union of function is a type you don't want to end up with. It is useless. In order to make it work you need to use intersection & of functions instead of union |, which in turn produces function overloading. Try this. If it still don't work please provide reproducible example Commented Jun 23, 2022 at 10:19

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.