TypeScript 从使用的参数推断 return 类型

TypeScript infer return type from used arguments

我不确定是否有人用不同的术语问过这个问题。我有一个带有两个参数的函数,其中两个参数都可以(独立地)是 numberstringundefined。 returned 值静态保证也是这两个参数之一:

export function wideNarrow(wide:number|string|undefined, 
                           narrow:number|string|undefined){
    return isNarrowScreen() ? narrow : wide;
}

在我的应用程序的某些部分,我将两个数字传递给函数:

wideNarrow(8, 0);

然而,推断出来的return类型是string|number,这说明数值运算出错:

const extendedAreaHeight = 26;
const baseY = extendedAreaHeight + wideNarrow(8, 0);

Operator '+' cannot be applied to types '26' and 'string | number'.ts(2365)

Object is possibly 'undefined'.ts(2532)

可以静态推断这个特定的调用将总是 return一个数字,为​​什么TypeScript没有检测到它并且仍然认为一个字符串或未定义可能是returned,以及如何在不破坏现有功能的情况下修复它(例如,我可能 return undefinedstringstringnumberundefinednumber 以及它们在我调用该函数的其他地方的任意组合)?

我正在使用 TypeScript 3.5.2/Vscode 1.36.1.

您可以添加更精确的函数声明,如下所示:

export function wideNarrow(wide: number, narrow: number): number;
export function wideNarrow(wide: number|string|undefined, narrow: number|string|undefined) {
    return isNarrowScreen() ? narrow : wide;
}

该函数仍然只有一个实现,但有多个声明,这有助于编译器。请参阅 Function Overloads 文档部分。

正如 Thomas 所建议的(我同时发现),使用两个具有相同签名的类型参数可以解决问题:

export function wideNarrow
  <T=number|string|undefined,
   K=number|string|undefined> 
   (wide:T, narrow:K){
  return isNarrowScreen() ? narrow : wide;
}

使用两种确切类型而不是一种的原因是它们可能与我在问题中所述的不同。如果我只做 T 而没有 K 并且同时做 widenarrow 类型的 T,它会强制 wide 和 [=14] =] 是相同的类型(例如,两个 numbers),而我有时需要它们是不同的类型(例如,宽 string 但窄 number)。

注意:如果有人真的想知道在什么情况下我需要这种方式,我正在使用它来填充我的 React Native 应用程序中的样式表,其中一些样式元素对两者都非常满意numbers 例如(width: 100 的 100 点宽)或 strings(例如 width: '50%')用于水平填充容器的一半)。