我试图让TypeScript使用Array.includes()正确地推断一些变量,但它不起作用。下面是一个简单的例子:
const Array = ['a', 'b', 'c'] as const
type SomeType = {
a: string
b: string
c: string
foo: boolean
bar: boolean
}
现在让我们假设我有一个函数,它接收SomeType的键,但实际上我只想在我的键在我的Array中时做一些事情
const myAwesomeFunction = (field: keyof SomeType): void => {
if (Array.includes(field) doStuff(field)
}
这里,给doStuff函数的字段类型应该是typeof Array
,但实际上是keyof SomeType
我猜这种行为是由于一些模糊的边缘情况,但我想找到一个解决办法,或者至少了解上面代码的根本问题,为什么Typescript认为这是一个错误
我发现了一些关于GH的问题,但我不能真正理解这一切:
- 问题1
- Issue 2
1条答案
按热度按时间jv4diomz1#
目前,the
includes()
array method的TypeScript类型不允许它在其输入上充当类型保护。这在microsoft/TypeScript#36275上被提出,但由于太复杂而无法实现而被拒绝。不允许它的原因与includes()
返回false
时的含义有关。true
的结果很容易推理;如果arr.includes(x)
是true
,那么当然x
必须与arr
的元素具有相同的 * 类型 *。但是如果arr.includes(x)
是false
,那么说x
的类型 * 不是 *arr
的元素的类型往往是错误的。例如,考虑一下这里会发生什么:值
x
是string
或number
类型。如果[1, 2, 3].includes(x)
是true
,那么我们知道x
是number
。但如果它是false
,我们绝对不能断定x
是string
。但如果includes()
是一个类型保护函数,就会发生这种情况。没有内置的支持说“哦,忽略否定的情况”。这就需要类似于“单侧”或“细粒度”类型保护函数的东西,正如您提到的问题之一microsoft/TypeScript#15048中所要求的那样。这种变化会立即引起注意和不愉快,因为整个使用TypeScript的世界中的
includes()
调用会突然看到非常奇怪的效果,它们的搜索值被错误地缩小,可能一直到never
类型。因此,使其成为类型保护的天真方法将是一个问题。我们可以尝试更复杂,只允许函数在像您的代码这样的情况下充当类型保护,其中数组元素类型是文字类型的联合。但这看起来更加复杂和奇怪,涉及conditional types和
this
参数,可能如下所示:它试图检测
T
是否是字符串文字类型,而不是string
本身,然后它使函数充当类型保护。但即使是 that 也不安全,因为没有任何东西要求数组包含其类型的每个元素:这在实践中可能不太可能,但这是一个并发症。即使我们不关心这一点,向全局可用函数添加新的奇怪调用签名也会对其他人的代码产生明显的影响。(推理会用重载函数做一些奇怪的事情,见ms/TS#26591和无数其他函数)。仅仅为了支持这一个用例,不值得所有TypeScript付出努力和风险。
如果你只做一次,我建议你坚持并继续:
否则,你可以将它 Package 在你自己的自定义类型保护函数中,并在需要这种行为时使用它:
或者,如果您真的想在代码库中的任何地方看到这种行为,您可以将调用签名合并到
Array<T>
接口中;这就是如果microsoft/TypeScript#36275被接受的情况,但它不会影响其他任何人。Playground链接到代码