BT101
BT101

Reputation: 3836

Typescript with union types

I have a generic function fetcher which accepts a callback parameter. This callback will be executed in the fetcher function later on (I'm using Vue composables pattern here). Further, these callbacks accepts different parameters as an argument. I've typed fetcher callback that accepts "params" parameter as an union type of possible params. Then I can use this fetcher function and pass callbacks with different parameters.

Code example:

type Param1 = {
  a: string;
}
type Param2 = {
  a: string;
  b: string;
}
type Params = Param1 | Param2
declare function fetcher(func: (params: Params) => void): void
declare function testFunc(obj: Param2): void
fetcher(testFunc)

Typescript error:

Argument of type '(obj: Param2) => void' is not assignable to parameter of type '(params: Params) => void'.
  Types of parameters 'obj' and 'params' are incompatible.
    Type 'Params' is not assignable to type 'Param2'.
      Property 'b' is missing in type 'Param1' but required in type 'Param2'.(2345)

How can I type fetcher function and pass a callback with declared params, like Param1 or Param2 which fetcher can accept?

Playground example

Upvotes: 0

Views: 200

Answers (1)

jblew
jblew

Reputation: 565

TLDR: declare function fetcher(func: (params: Param1 & Param2) => void): void

Explanation:

The declaration:

declare function fetcher(func: (params: Param1 | Param2) => void): void

Instructs the compiler that func must support both Param1 and Param2 types.

Remember:

{ a: string; b: string } | { a: string; } !== { a: string; } & { b?: string }

Type union for function arguments:

  1. means that the function can handle both the situations: {a} and {a,b}
  2. does not mean that parameter {b} is optional, so {a}|{a,b} != {a,b?}

If you want to tell the compiler that fetcher accepts either func(p: Param1) or func(p: Param2) you have two possibilities:

// 1:
declare function fetcher(func: (params: Param1 & Param2) => void): void

// 2:
declare function fetcher(func: ((p: Param1) => void) | ((p: Param2) => void)): void

And the second one is more semantically correct as it tell the compiler that functions with both arguments are welcome.

Upvotes: 1

Related Questions