微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用通用约束时,类型缩小无法按预期工作

如何解决使用通用约束时,类型缩小无法按预期工作

我有一种情况,泛型类型受到联合类型的约束,但我发现这样做不会使类型缩小以按预期工作。下面的代码片段显示了正在发生的事情。

function somefunc<T extends string | number>(input: T): T {
  if (typeof input === "string") {
    // expecting input to be of type "string"
    // but input becomes of type T & "string"
    input
  } else {
    // expecting input to be of type "number"
    // but input becomes of type T extends string | number
    input
 }
}

如果我取消泛型,只将函数参数注释为 string | number 就可以了,但对于我的用例,我需要有泛型约束。

编辑

用例基本上是尝试将其与条件类型一起使用。基本上我想让结果类型成为取决于输入类型的条件类型。所以当输入类型为number时,结果也是number,当输入类型为string时结果也变成string。基本上是这样的:

type Result<T> = T extends string ? string : number

function somefunc<T extends string | number>(input: T): Result<T> {
  if (typeof input === "string") {
    // expecting input to be of type "string"
    // but input becomes of type T & "string"
    input
  } else {
    // expecting input to be of type "number"
    // but input becomes of type T extends string | number
    input
 }
}
 

我可能遗漏了一些东西,但问题是,我如何拥有基于联合的泛型约束并按照我的预期进行类型缩小工作。在上面的代码中,这意味着,在 if 分支中,input 变为类型 string 而在 else 分支中,它变为 number(或在至少它变成了 T & number)

** 编辑 **

我能够使用函数重载来实现我想要的。我只是想知道使用泛型和条件类型是否可以实现同样的事情。

解决方法

未缩小的原因在this answer

中说明

正确缩小类型的黑客方法:

type Result<T> = T extends string ? string : number;

function somefunc<T extends string | number>(input: T): Result<T> {
  const inputNarrowed: string | number = input;

  if (typeof inputNarrowed === "string") {
    inputNarrowed; // string
  } else {
    inputNarrowed; // number
  }

  return inputNarrowed as Result<T>;
}

重载+条件泛型的替代解决方案(我更喜欢)

type Result<T> = T extends string ? string : number;

function somefunc<T extends string | number>(input: T): Result<T>;
function somefunc(input: string | number) {
  if (typeof input === "string") {
    input; // string
  } else {
    input; // number
  }

  return input;
}

const str = somefunc("string"); // string
const num = somefunc(1); // number

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。