我在try 键入与以下示例中的函数类似的函数时遇到了一些问题

type Type = {
  x: string
}

function func<T extends Type>(v: T): boolean
function func<T extends Type>(v: T | null): boolean | undefined {
  return true
}

const getValue = (): Type | null => {
  return null
}
let x = getValue()
func(x)

但我收到以下消息,因为编译器似乎正在try 解析第一个函数定义的泛型

No overload matches this call.
  Overload 1 of 2, '(v: null): undefined', gave the following error.
    Argument of type 'Type | null' is not assignable to parameter of type 'null'.
      Type 'Type' is not assignable to type 'null'.
  Overload 2 of 2, '(v: Type): boolean', gave the following error.
    Argument of type 'Type | null' is not assignable to parameter of type 'Type'.
      Type 'null' is not assignable to type 'Type'.

我try 在在线TS编译器中编写该函数的更简单版本.我希望编译器告诉我它是一个有效的函数

推荐答案

在TypeScrip中重载函数的诀窍是last function argument declaration.TypeScrip ignoreslast声明externally来自该函数,并且仅使用该声明来键入inside函数签名.

最后一个声明需要满足all个重载,您可以在function overloads的打字脚本文档中看到这一点.要做到这一点,最简单的方法是传递所有参数并返回值为any.

function func(v: number): number
function func(v: string): string
function func(v: any): any {
  return v;
}
func(false); // still throws type error - see note with error below

在外部,您可以only使用数字或字符串调用此函数.因此,如果我try 使用false调用它,它仍然会抛出一个类型错误.因此,这验证了上一个函数声明仅用于内部类型,只要它们满足所有重载.还要注意的是,该错误仅指2过载not3.

func(false);
     ^^^^^
No overload matches this call.
Overload 1 of 2, '(v: number): boolean', gave the following error.
  Argument of type 'boolean' is not assignable to parameter of type 'number'.
Overload 2 of 2, '(v: string): boolean | undefined', gave the following error.
  Argument of type 'boolean' is not assignable to parameter of type 'string'.(2769)

但是这种键入any的方法是不精确的,并且在函数签名中提供了非常松散的类型.一种better的方式是对每个函数重载参数和返回值求值为union.所以在这个简单的例子中它看起来像...

function func(v: number): number
function func(v: string): string
function func(v: number | string): number | string {
  return v;
}
func(1) // no error
func('string') // no error
func(false) // throws type error

因此,在您的情况下,您可以简单地使用此代码.

type Type = {
  x: string
}

function func<T extends Type>(v: T): boolean
function func<T extends Type>(v: T | null): boolean | undefined
function func<T extends Type>(v: T | null): boolean | undefined {
  return true
}

const getValue = (): Type | null => {
  return null
}

let x = getValue()

func(x) // no more errors

是的,这是重复第二个重载声明,这不是一个错误,这是必需的!删除此重复声明会使代码错误成为原始代码.请参阅上面讨论的与最后一个函数声明相关的推理.

请参阅工作TS操场演示here

仅供参考-当每个重载声明有多个不同的泛型和/或参数/返回时,满足所有类型会变得更加困难.在这一点上,取消any的类型(选项1)成为一个明智的 Select .

Typescript相关问答推荐

处理API响应中的日期对象

用泛型类型覆盖父类函数导致类型y中的Property x不能赋给基类型Parent中的相同属性."'''''' "

替代语法/逻辑以避免TS变量被分配之前使用." "

使用带有RxJS主题的服务在Angular中的组件之间传递数据

有没有一种方法可以在保持类型的可选状态的同时更改类型?

为什么typescript不能推断类的方法返回类型为泛型''

如何使用泛型类型访问对象

如何在TypeScrip中使用嵌套对象中的类型映射?

对于合并对象中的可选属性(例如选项),类型推断可能是错误的

TypeError:正文不可用-NextJS服务器操作POST

剧作家元素发现,但继续显示为隐藏

在React中定义props 的不同方式.FunctionalComponent

避免混淆两种不同的ID类型

设置不允许相同类型的多个参数的线性规则

任何导航器都未处理有效负载为";params";:{";roomId";:";...";}}的导航操作

如何在TypeScrip中使用数组作为字符串的封闭列表?

React Context TypeScript错误:属性';firstName';在类型';iCards|iSearch';

数据库中的表请求返回如下日期:2023-07-20T21:39:00.000Z 我需要将此数据格式化为 dd/MM/yyyy HH:mm

使用 fp-ts 时如何使用 TypeScript 序列化任务执行?

如何让 Promise 将它调用的重载函数的类型转发给它自己的调用者?