相似类型约束和条件类型的区别

Difference in between similar type constraint and conditional type

我自己编写了内置实用程序类型的实现 InstanceType:

type MyInstanceType<C extends abstract new (...args: any) => any>
  = C extends abstract new (...args: any) => infer R ? R : never

它与实际实现的方式非常接近:

type BuiltInInstanceType<C extends abstract new (...args: any) => any>
  = C extends abstract new (...args: any) => infer R ? R : any

唯一不同的是,我说的是最后一句话 never,而实际的实施却在那里 any

这导致它对待方式的不同 any:

type MyWithAny = MyInstanceType<any> // unknown
type BuiltInWithAny = BuiltInInstanceType<any> // any

我认为这意味着它以某种方式到达了条件类型的虚假分支

所以问题是,这怎么可能?考虑到条件类型与类型约束相同,因此对条件类型为假的任何内容对于类型约束也应为假,因此应导致类型约束失败错误

第二个问题,为什么 MyWithAny 恰好是 unknown 而不是例如never?

UPD:根据答案和讨论,这就是它的评估方式(接受的答案中有更多详细信息):

  1. 在评估 MyWithAnyBuiltInWithAny 时,使用 any 作为泛型函数的参数已完全禁用类型约束。所以 MyInstanceType 被评估为
type MyInstanceType<C> = C extends abstract new (...args: any) => infer R ? R : never

BuiltInInstanceType 已被评估为

type BuiltInInstanceType<C> = C extends abstract new (...args: any) => infer R ? R : any

这使得伪分支成为可能

  1. 如果 TS 无法评估条件类型的分支,它将其评估为两个分支的联合类型。因此,由于 any 包含可能满足或不满足条件类型的实例,因此 MyWithAny 的类型变为 R | never 并且 BuiltInWithAny 的类型变为 R | any
  2. 如果 TS 无法解析 R,则认为是 unknown。所以,MyWithAny的结果类型是unknown | neverunkonownBuiltInWithAny的结果类型是unknown | anyany

你的例子可以简化成这样:

type WithNever = <T>(t: T) => T | never
type WithAny = <T>(t: T) => T | any

type NeverRetutn = ReturnType<WithNever>
type AnyRetutn = ReturnType<WithAny>

我们对 T | neverT | any 感兴趣。

如果 TypeScript 无法推断 T 的类型,TS 将分配 unknown 类型。

参见示例:

type ReturnUnknown = ReturnType< <T>(t: T) => T> // unknown

什么是never? (docs)

The never type is a subtype of, and assignable to, every type

实际上,您应该将 never 视为空联合。

type Check = 1 | never // 1
type Check2 = unknown | never // unknown
type Check3 = any | never // any

您可能已经注意到,never 分配给了每种类型。

让我们回到你的问题。事实上,您正在接收类型联合。

type MyWithAny = MyInstanceType<any> // R | never
type BuiltInWithAny = BuiltInInstanceType<any> // R | any

我希望,现在很清楚,R | never 将被解析为 unknown,因为 R 是未知的,而 never 可分配给未知。

R | anyunknown | any 相同,并且因为任何类型都可以分配给 any,所以您得到的只是 any.

但是为什么你会收到类型的联合? 很明显,条件类型应该 return true 或 false 分支,但不能两者兼而有之。这不是它在 TS 中的工作方式。

因为您提供了 any 作为参数,所以每个分支都会被应用。我认为这是意料之中的,因为我没有足够的论据说应该只应用 true 分支,或者只应用 false 分支。

Considering that conditional type is the same as type constraint and so anything that is falsy to the conditional type should also be falsy to type constraint and so should result in a type constraint failed error

既然any类型实际上是任何类型(每种类型),你认为为什么要应用false分支?请记住,您使用的是类型,而不是值。

What is confusing to me about falsy branch is that how I understand it, it should always be evacuated to never, no matter what we put there

它不能总是被评估为假分支。这样的假设是不正确的。

考虑下一个例子:

type CheckAny = any extends abstract new (...args: any) => any ? true : false

以上条件的计算结果为 true | falsetrue | false union 只是一个内置的 boolean 类型。

我不认为打字稿不够聪明。 TS只是告诉你 any 类型可以扩展构造函数类型,但同时它不能扩展。