将 any 与 void 进行比较时,为什么类型是联合?

When comparing any to void why is the type a union?

我想检查提供的类型是否为 void 并且惊讶地发现在传入 any 时返回了一个联合。有人可以解释这是为什么吗?

type test<T> = T extends void ? void extends T ? 1 : 0 : 0;

type v1 = test<any>; // 1 | 0
type v2 = test<unknown>; // 0
type v3 = test<undefined>; // 0
type v4 = test<null>; // 0
type v5 = test<never>; // never
type v6 = test<void>; // 1
type v7 = test<boolean>; // 0
type v8 = test<string>; // 0
type v9 = test<number>; // 0
type v10 = test<'void'>; // 0
type v11 = test<{}>; // 0

Playground

查看真假分支的 microsoft/TypeScript#40049 for an authoritative answer. When any is checked via a conditional type, the result will be the union。这可能令人惊讶,但它正在按预期工作。

相关评论:

This isn't especially well-documented outside of the source-code, but in the checker you'll find in the relevant place:

// Return union of trueType and falseType for 'any' since it matches anything
if (checkType.flags & TypeFlags.Any) {

So any is treated like a wildcard that matches both branches.

我想我理解了这一点:

void extends any ? 1 : 0 解析为 1,意思是 void 确实扩展了 any。我想这是 Typescript 作者的设计决定,我找不到原因。根据我的测试 - 所有类型都扩展 any(用 {}, () => 1, "v", 3, unknown 检查)。

然后,any extends void ? 1 : 0 解析为 1 | 0,这实际上是有意义的(它将是条件类型中的两种类型之一)。

结果

 ==> test<any>
     === any extends void ? void extends any ? 1 : 0 : 0
     === any extends void ? 1 : 0
     === 1 | 0

Playground