我想我知道为什么下面的代码编译失败了(playground):
type Type = [unknown] & { type: unknown };
interface $Zeros extends Type {
// ~~~~~~
// Type instantiation is excessively deep...
type: Zeros<this[0]>
}
type Zeros<N, R extends unknown[] = []> =
N extends R['length'] ? R : Zeros<N, [0, ...R]>;
问题是this[0]
就是unknown
,所以TS试图扩展Zeros<unknown>
,由于我在Zeros
中表达条件的方式,它无限地重复。
这是我的假设,因为翻转条件句可以化解它(playground):
// no error with this implementation
type Zeros<N, R extends unknown[] = []> =
R['length'] extends N ? R : Zeros<N, [0, ...R]>;
但是,当我将Type
的实现替换为以下实现时,我不再遇到此错误:
type Type = { 0: unknown, type: unknown }
我甚至可以毫无问题地直接查询该值:
type GetZeros = ($Zeros & [3])['type'];
然而,如果我在一个类型中提取这个逻辑,那么它就不会再编译了(而且在Zeros
中翻转条件的方法是相同的):
type apply<$T extends Type, Args> = ($T & Args)['type'];
type applyZeros = apply<$Zeros, [3]>;
// ~~~~~~~~~~~~~~~~~~
// Type instantiation is excessively deep...
(上述设置的Playground)
我对最后一个片段的行为同样感到惊讶:我期望this[0]
是3
,所以Zeros
应该被输入3
,N extends R['length']
应该是3 extends R['length']
,所以不应该有无限递归...
很明显,我的思维模式在这个例子中有两个明显的地方失败了。我需要一些洞察力。到底发生了什么?
添加一些上下文
以上是我在library上实验的两个设计的简化版本。{ 0: unknown, type: unknown }
实现有很多优点,也是我目前正在使用的一个,但我更喜欢[unknown] & { type: unknown }
的行为,因为它可以帮助用户更容易、更快地找到错误的原因。
在库的正常使用过程中,即使没有应用“参数”,$Zeros['type']
也应该被其他类型查询(以检查它是否可以组合),因此this[0]
是unknown
(或某些类型约束)的情况以及诸如无限递归或无用/退化返回类型等潜在问题由实现者处理是很重要的。
1条答案
按热度按时间gajydyqb1#
好吧,贝娄是一个解释性的模型,它不是经典,但对我来说足够好了,我很乐意被反驳。
Type
为元组时的过早求值在下面的代码中,不计算接口
$Zeros
中的type
字段但是,它将使用以下单个变更进行评估:
交集类型
[unknown] & { type: unknown }
导致添加索引签名,如下面的代码所示:基本原理是,当接口包含索引签名时,类型检查器无法对对象上存在的属性做出假设,因此在
$Zeros
的情况下,它无法确定字段0
是否存在或其类型是什么,即使键0
显式地存在于Type
的定义中。因此,TS必须评估type
字段以确保它是格式良好的。尝试演示这一点的一种方法是使用实用程序类型移除索引签名
那么我们需要稍微修改一下
$Zeros
的定义,因为如果没有索引签名,数组只能用字符串键来索引:上述情况不会触发无限递归错误。
使用实用程序类型
apply
时的错误可以观察到,通过将鼠标悬停在操场中的
applyZeros
上可以推断出正确的返回类型([0, 0, 0]
),因此触发错误的不是推理引擎。罪魁祸首是类型检查器,因为它继续用
$T = $Zeros
检查$T extends Type
。实际上,
apply
的以下实现没有出现这个问题:我的理解是,类型约束
$T extends { type: unknown }
导致类型检查器将Zeros<this[0]>
计算为Zeros<unknown>
,这导致无限递归。我认为这个求值是不必要的,因为
T extends unknown
总是真的,并且可以跳过总是真的检查,而不是求值类型,我认为简单地检查键是否存在就足够了。我提交了一份bug report