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

标签 typescript type-constraints conditional-types

我已经编写了自己的内置实用程序类型 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 而不是例如从不?

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 |从不 并且 BuiltInWithAny 的类型正在变为 R |任何
  2. 如果 TS 无法解析 R,它会认为是 unknown。所以,MyWithAny 的结果类型是unknown | neverunkonownBuiltInWithAny 的结果类型为unknown |任何任何

最佳答案

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

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

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

我们对 T | 感兴趣从不T |任何

如果 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 可分配给 unknown。

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

但是为什么你会收到类型的联合? 很明显,条件类型应该返回 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 |错误。和 true | false union 只是一个内置的 boolean 类型。

我不认为 typescript 不够聪明。 TS 只是告诉你,任何 类型都可以扩展构造函数类型,但同时它不能扩展。

关于typescript - 相似类型约束和条件类型的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68435374/

相关文章:

Typescript - 基于类属性的条件返回类型

angularjs - 捕获 403 Angular 错误并显示弹出窗口

javascript - Karma + JSPM + Typescript - 未找到 '.ts.js'

haskell - 排名 n 约束? (或者,monad 转换器和 Data.Suitable)

haskell - 是否可以将其他类型变量引入父类(super class)约束?

typescript - 联合数据类型上的条件数据类型

typescript - 基于条件类型的可选参数

javascript - 使用 switchMap 发出一个热 bool 值 observable?

javascript - 导致循环依赖的子实例

c# - 如何将对象转换为具有公共(public)无参数构造函数以遵守 : new() constraint?