打字稿中的重载函数类型

Posted

技术标签:

【中文标题】打字稿中的重载函数类型【英文标题】:Overloaded function type in typescript 【发布时间】:2019-02-07 11:45:49 【问题描述】:

如何在不提供具体函数的情况下创建重载的函数类型? 通过检查重载函数的类型,似乎可以在接口/对象类型上使用多个调用签名:

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!

用联合类型定义相同的想法(没有那种令人讨厌的包罗万象的情况,你需要让重载快乐)也有效,类型在两个方向上都兼容!

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

const c: C = b // Okay!

const a2: A = c // Okay too!

但是我现在如何制作适合这种类型的函数呢?我是否也必须使用重载?

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

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

两者都失败并出现完全相同的以下错误:

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'.

最糟糕的是,即使我使用可读性较差的联合类型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'.

希望我做错了什么,并且有一个简单的解决方法。 否则,当我需要要求在某处传递的函数处理具有相应返回类型的多个调用签名时,我最好的选择是什么?

【问题讨论】:

【参考方案1】:

您可以使用generic 声明解决此问题:

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!

至于xy,您不能松散地定义参数类型并期望严格推断输出类型。如果您要将xy 声明为A 类型,请省略定义函数的输入类型:

const x: A = input => input

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

您可以在TypeScript Playground demo 验证上述所有内容。

【讨论】:

非常抱歉,x 函数中有错字。正确的 x (const x: A = (input: Input) =&gt; input) 和 y 仍然失败,现在在这种情况下使用 Type '(input: Input) =&gt; Input' is not assignable to type '&lt;T extends Input&gt;(input: T) =&gt; T'. Type 'Input' is not assignable to type 'T'. Type 'string' is not assignable to type 'T'. 这里:typescriptlang.org/play/… 这是因为您在将 xy 函数声明为更严格的类型时定义的输入太弱。请参阅我的更新答案。 这确实修复了通用示例。但是我如何输入一个不是恒等函数的函数呢?比如返回相反的类型? 示例:(B 接受,正文没有)typescriptlang.org/play/…【参考方案2】:

要定义具有多个调用签名的函数,如果您无法编写一个可分配给您想要的所有调用签名的单个调用签名,您将不得不使用任一重载(它具有更宽松的兼容性规则带有实现签名的调用签名)或类型断言。你没有错过任何东西。

【讨论】:

但是我如何使用匿名函数来实现这种类型呢? 如果你想使用匿名函数而不是本地重载函数定义,你必须使用类型断言。 :'( keystrokes keystrokes

以上是关于打字稿中的重载函数类型的主要内容,如果未能解决你的问题,请参考以下文章

基于可选参数存在而不使用函数重载的打字稿函数返回类型

打字稿重载、可选参数和类型推断

如何在打字稿中声明函数类型

获取泛型函数的类型而不调用打字稿中的函数

再次:打字稿函数重载

在打字稿中实现函数重载