简体   繁体   中英

Overloaded function type in typescript

How can I create a function type, without providing a concrete function, that is overloaded? By inspecting the type of an overloaded function, it seems multiple call signatures on an interface/object type are the way to go:

function a(input: string): string
function a(input: number): number
function a(input: string | number): string | number {
  return input
}

type A = typeof a

type B = {
  (input: string): string
  (input: number): number
}

const b: B = a // Okay!

Defining the same idea with a union type (without that pesky catch-all case that you need to make overloads happy) also works , the types are compatible in both directions!

type C = ((input: number) => number) & ((input: string) => string)

const c: C = b // Okay!

const a2: A = c // Okay too!

But how do I now make a function fitting this type? Do I have to necessarily also use overloading?

const x: A = (input: string | number) => input

and

const y: A = (input: string | number) => {
  if (typeof input === "number") return input
  if (typeof input === "string") return input
  throw "excrement"
}

both fail with the exact same following error:

Type '(input: string | number) => string | number' is not assignable to type '{ (input: string): string; (input: number): number; }'.
  Type 'string | number' is not assignable to type 'string'.
    Type 'number' is not assignable to type 'string'.

Worst of all, this happens even if I use the less readable union type C

Type '(input: string | number) => string | number' is not assignable to type 'C'.
  Type '(input: string | number) => string | number' is not assignable to type '(input: number) => number'.
    Type 'string | number' is not assignable to type 'number'.
      Type 'string' is not assignable to type 'number'.

Hopefully, I am doing something obvious wrong and there's an easy fix. Else, what are my best options when I need to demand that a function that is passed somewhere handle several call signatures with corresponding return types?

To define a function with multiple call signatures, if you're not able to write a single call signature that is assignable to all the call signatures you want, you will have to use either overloading (which has looser rules for compatibility of the call signatures with the implementation signature) or a type assertion. You aren't missing anything.

You can solve this using a generic declaration:

type Input = string | number

function a<T extends Input>(input: T): T {
  return input
}

type A = typeof a

type B = {
  (input: string): string
  (input: number): number
}

const b: B = a // Okay!

type C = ((input: number) => number) & ((input: string) => string)

const c: C = b // Okay!

const a2: A = c // Okay too!

As for x and y , you cannot define the parameter type loosely and expect the output type to be inferred strictly. Omit defining the input types for the functions if you're going to declare x and y as type A :

const x: A = input => input

const y: A = input => {
  if (typeof input === "number") return input
  if (typeof input === "string") return input
  throw "excr"
}

You can verify everything above works at this TypeScript Playground demo .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM