我正在编写一个函数,当输入为假时,该函数返回 undefined。在 TypeScript 5.6.2 中,我无法让以下示例通过类型检查器:
// Return type: number | "" | undefined
const f1 = (s: string, n: number) => (s || undefined) && n;
// Type 'number | "" | undefined' is not assignable to type 'number | undefined'.
// Type 'string' is not assignable to type 'number'.(2322)
const x: number | undefined = f1("a", 1);
推断的返回类型表明f1
可能返回空字符串。这很烦人,因为我需要处理不可能的字符串返回类型。我认为返回类型应该是number | undefined
。
当字符串和数字交换时也会发生同样的事情:
// Return type: string | 0 | undefined
const f2 = (s: string, n: number) => (n || undefined) && s;
当我使用三元运算符或强制转换为布尔值时,返回类型被正确推断:
// Return type: number | undefined
const f3 = (s: string, n: number) => (s ? true : undefined) && n;
// Return type: number | undefined
const f4 = (s: string, n: number) => (!!s || undefined) && n;
TypeScript 的类型系统表达能力不足以表示“真值
string
”,从而影响控制流分析。只有文字类型 的空字符串""
才是假值,因此除空字符串之外的所有字符串都是真值。但为了表示“除空字符串之外的所有字符串”,TypeScript 需要类似microsoft/TypeScript#4183中要求的减法类型或microsoft/TypeScript#4916中要求的否定类型。它两者都没有。所以没有或。string ~ ""
string & not ""
如果存在这样的类型,那么大概
s || undefined
会是这样的(string & not "") | undefined
(因为如果逻辑 OR (||
)为真,则计算结果为其第一个操作数,否则计算结果为其第二个操作数,因此会得到第一个操作数与第二个操作数的真值部分)。然后(s || undefined) && n
会是这样的number | ("" & not "") | undefined
,它会简化为number | undefined
(因为如果逻辑 AND (&&
)为假,则计算结果为其第一个操作数,否则计算结果为其第二个操作数,因此会得到第一个操作数与第二个操作数的假值部分)。实际情况是 是
s || undefined
类型string | undefined
,它不可能是 的事实""
被忽略了。然后(s || undefined) && number
计算第一个操作数 (string | undefined
) 联合的假值部分,因为string | undefined
当且仅当它的值为 时才是假值"" | undefined
,所以与 联合后的结果就是number
。TypeScript 会丢失“不可能是""
”的踪迹。这也解释了当和切换时如何
0
显示。是唯一的falsy ,但没有或来表达truthy 。string
number
0
number
number ~ 0
number & not 0
number
为了澄清您的问题,您问的是,since
f5
具有以下返回值:f1
那么,如果我们所做的只是使用逻辑 AND 运算符(),为什么会有以下返回类型&&
?答案在于逻辑“与”运算符的定义:
在我们的例子中,我们有
(s || undefined) & n
。这转换为类型(string | undefined)
与类型的逻辑与number
。查看string | undefined
操作数,可能的假值是undefined
和""
(空字符串)。当我们应用逻辑与运算符时,如果结果为假值(或(s || undefined)
之一),则该假值将是逻辑与的结果。undefined
""
这些假值与第二个操作数的类型进行逻辑与运算
number
以获得undefined | "" | number
。证明这一点的一个例子是删除逻辑或:
要明确输入你的函数
f1
,只需手动缩小它的范围: