打字稿在元组联合中缩小范围

Posted

技术标签:

【中文标题】打字稿在元组联合中缩小范围【英文标题】:Typescript narrowing down within union of tuples 【发布时间】:2021-06-22 17:03:49 【问题描述】:

假设我有这样的功能:

function foo(n: number): [number, undefined] | [undefined, number] 
  if (n % 2 === 0) 
    return [n, undefined];
  
  return [undefined, n];

然后像这样调用这个函数:

function bar() 
  const [a, b] = foo(2);
  if (a === undefined) 
    return b; // TypeScript infers b as number | undefined
  
  return a; // TypeScript infers a as number (good!)

由于函数 foo 返回元组 (number, undefined)(undefined, number),在没有通过 a === undefined 检查后,TypeScript 能够在返回时推断 a 的类型是数字。

if 块内,因为a 未定义,我们(人类)可以将此处的foo 的返回类型推断为[undefined, number],因此b 的类型为数字。然而,TypeScript 似乎不够聪明,无法分辨这一点,并报告说它是number | undefined

是否有缩小元组联合范围的解决方法?

【问题讨论】:

在 Typescript 3.9.7 上按原样编译。这可能是在较新的 TS 版本中修复的问题吗? 对不起,不够清晰。它编译得很好,但我想要的是 bar 函数的返回类型是数字(因为理论上它应该是),但它被推断为数字 |未定义。 @SilvioMayolo 您是否启用了 strictNullChecks?这对我来说会引发编译器错误。 啊,这样就行了。好点子。我现在可以复制了。 【参考方案1】:

TypeScript 的区分联合不会跟踪ab 之间的依赖关系,因此在您解构数组后,缩小a 不会影响b 的类型。要仍然实现所需的缩小,您可以直接测试数组元素,如下所示:

function bar() 
  const arr = foo(2);
  if (arr[0] === undefined) 
    const b = arr[1]
    return b; // TypeScript infers b as number (good!)
  
  const a = arr[0]
  return a; // TypeScript infers a as number (good!)

TypeScript playground

【讨论】:

【参考方案2】:

截至版本。 4.6,TypeScript 现在处理 Destructured Discriminated Unions 并且您的代码 sn-p 将不再出错。

TypeScript playground

function bar() 
  const [a, b] = foo(2);
  if (a === undefined) 
    return b; // TypeScript infers b as number (good!)
  
  return a; // TypeScript infers a as number (good!)

TypeScript 4.6 RC - [link]

【讨论】:

以上是关于打字稿在元组联合中缩小范围的主要内容,如果未能解决你的问题,请参考以下文章

打字稿从元组/数组值派生联合类型

打字稿在vscode中找不到名称'test'

如何使用打字稿在reactjs中传递数据

使用打字稿在reduce方法中使用扩展语法进行解构

使用打字稿在 Firebase Cloud 函数中动态导入类的正确方法是啥?

如何通过打字稿在Formik中添加强类型字段?