当前位置: 首页 > 知识库问答 >
问题:

使用条件返回类型实现泛型函数

洪琦
2023-03-14

我正在尝试一个非常基本(人为)的条件类型函数,但遇到了意外错误:

function test<
  T
>(
  maybeNumber: T
): T extends number ? number : string {
  if (typeof maybeNumber === 'number') {
    return maybeNumber // Type 'T & number' is not assignable to type 'T extends number ? number : string'.
  }

  return 'Not a number' // Type '"Not a number"' is not assignable to type 'T extends number ? number : string'.
}

我认为这是一个非常简单的条件类型用法,所以不确定发生了什么。有什么想法吗?

共有3个答案

尹光辉
2023-03-14

我认为您在错误的位置定义了返回类型:

function test<T extends number | String>(maybeNumber: T) {
if (typeof maybeNumber === 'number') {
  return maybeNumber
}
return 'Not a number'

}

长孙骏
2023-03-14

正确答案和当前的变通方法(在写作时):

type MaybeNumberType<T extends number | string> = T extends number
  ? number
  : string;

function test<T extends number | string>(
  maybeNumber: T,
): MaybeNumberType<T> {
  if (typeof maybeNumber === 'number') {
    return <MaybeNumberType<T>>(<unknown>maybeNumber);
  }

  return <MaybeNumberType<T>>(<unknown>'Not a number');
}

test(3); // 3
test('s'); // Not a number
钱经赋
2023-03-14

潜在的问题是TypeScript的编译器没有通过控制流分析缩小泛型类型变量的类型。当您检查(typeof maybeNumber==="数字")时,编译器可以将值maybeNumber缩小到数字,但它不会将类型参数T缩小到数字。因此,它不能验证将数字值分配给返回类型T扩展数字是否安全?数字:字符串。编译器将不得不执行一些它目前不做的分析,例如“好吧,如果typeof maybeNumber==="数字",我们仅从maybeNumber的类型推断T,那么在这个块内我们可以将T缩小为number,因此我们应该返回类型为number的值扩展数字?数字:字符串,又名数字。但这并没有发生。

对于具有条件返回类型的泛型函数来说,这是一个相当棘手的问题。关于这一点的规范性开放GitHub问题可能是microsoft/TypeScript#33912,但还有许多其他GitHub问题,这是主要问题。

这就是“为什么这行不通”的答案?

如果您对重构不感兴趣,那么可以忽略其余部分,但是知道在这种情况下应该做什么,而不是等待语言的更改,这可能仍然是有益的。

这里维护调用签名的最直接的解决方法是使函数成为单个签名重载,而实现签名不是泛型的。这实质上放松了实现内部的类型安全保证:

type MyConditional<T> = T extends number ? number : string;
type Unknown = string | number | boolean | {} | null | undefined;

function test<T>(maybeNumber: T): MyConditional<T>;
function test(maybeNumber: Unknown): MyConditional<Unknown> {
  if (typeof maybeNumber === 'number') {
    const ret: MyConditional<typeof maybeNumber> = maybeNumber;
    return ret;
  }
  const ret: MyConditional<typeof maybeNumber> = "Not a number";
  return ret;
}

在这里,我已经尽我所能,通过使用一个临时ret变量(注释为MyConditional)来保证类型安全

function test2<T>(maybeNumber: T): MyConditional<T>;
function test2(maybeNumber: any): string | number {
  if (typeof maybeNumber === 'number') {
    return maybeNumber;
  }
  return "Not a number";
}

好吧,希望这会有帮助;祝你好运

操场连结至守则

 类似资料:
  • 我正在尝试创建一个通用函数,它接受一个,并返回一个对象,该对象包含公共基类型的属性以及特定类型的默认值。出于某种原因,如果没有编译器的抱怨,我无法让它工作。我不确定问题出在哪里,但是 我怀疑这可能是将类型定义为条件类型的方式。我尝试过以各种方式重新定义我的类型,但没有成功,所以我怀疑我要么错过了一些明显的东西,要么没有类型断言是不可能的。 以下是我的类型: 以下是我的通用函数: 产生以下错误: 类

  • 我想通过TypeScript泛型定义函数返回类型。所以R可以是我将定义的任何东西。 <代码>。。。许诺 错误:(29,9)TS2322:类型“字符串”不可分配给类型“R”。“字符串”可分配给类型“R”的约束,但“R”可以用约束“{}”的不同子类型实例化。

  • 我试图创建一个返回泛型类型参数的方法。 我有一个类车辆订单扩展抽象类订单。在类订单中,我创建了一个抽象方法接收HiredObject。这个方法不会接收任何参数,并将返回一个泛型。 我在VehicleOrder类中实现了这个方法,并将其设置为返回类参数vehicle。 问题是,当我实例化一个新的VeilceOrderorororororororororororororderororororororo

  • (沙盒) 获取此错误: 类型“number”不可分配给类型“T”“number”可分配给“T”类型的约束,但“T”可以用约束{}的不同子类型实例化。(2322)输入。ts(1,26):预期类型来自此签名的返回类型。 我希望typescript能够自动推断T为数字,然后直接使用它。为什么它在抱怨?写这样的东西的正确方法是什么?谢谢

  • 假设我想写一个函数,它可以接受一个参数,这个参数可以是null类型,也可以是非null类型。如果参数不可为null,则返回类型也应不可为null。类似地,如果参数是可空类型,那么返回类型也应该是可空类型。 以下是我为实现这一职能所做的尝试: 函数签名似乎是正确的,因为它在调用站点上实现了所需的行为,例如: 即返回类型确实由参数类型以正确的方式确定。 然而,我的问题在于函数的实现。如果不将返回值强制

  • 对于一堆带有泛型的包装类,我的继承结构遇到了一些麻烦。这基本上是结构: 这将与当前代码一起编译和工作,但是,这似乎很危险。如果调用方像这样使用这个方法:,它将很好地编译,但是如果findMiddle尝试返回SubBWrapper,则在运行时会有一个ClassCastException。我以为行得通却行不通的是: 所以我的问题基本上是,有没有正确的方法来编写编译、运行并遵循最佳实践的方法findMi