提问人:Ooker 提问时间:9/20/2023 更新时间:9/20/2023 访问量:30
如何告诉 TypeScript 理解在 if 子句中使用 array.some() 已经缩小了类型范围?
How to tell TypeScript to understand that using array.some() in an if clause already narrows type?
问:
我有这个代码:
const list = ['a', 'b', '= c', 'd']
if (list.some(element => element.includes('='))) {
const elementWithEqualSign = list.find(element => element.includes('='))
}
这里有类型,而实际上它应该只是,由于上面的条件过滤了的可能性。有没有办法告诉它在不使用类型断言的情况下自动缩小类型范围?我想答案就在 TypeScript 的某个地方:文档 - 缩小范围,但我不知道要找出它。elementWithEqualSign
string | undefined
string
undefined
as string
答:
2赞
Roger Lipscombe
9/20/2023
#1
在一般情况下,不可以。
考虑以下情况:您在 中使用与 中的条件不同的条件。.some()
.find()
编译器如何(自动)确定第一个条件是否更改了 的返回类型。.find()
如果条件非常复杂怎么办?例如,如果它根据 REST API 检查每个元素,会怎么样?即使具有看似相同的条件,它也可能在第二次返回不同的结果(这有时称为检查时间-使用时间-TOCTOU),这意味着这是一种可能的类型。undefined
使用类型断言。
评论
0赞
Ooker
9/20/2023
如果我使用相同的回调,并且它只有一种类型的输出怎么办?
0赞
mbojko
9/20/2023
类型断言或非 null 断言运算符:。const elementWithEqualSign = list.find(element => element.includes('='))!;
1赞
Dimava
9/20/2023
#2
好吧,不要这样做,但
https://tsplay.dev/mLJBZw
interface Array<T> {
// make "some" to say it has the item
some<V>(predicate: (v: T) => v is T & V): this is { guaranteedHas: V };
// make "find" to get the item if it has it
find<V>(this: { guaranteedHas: V }, predicate: (v: T) => v is T & V): V;
}
interface ReadonlyArray<T> {
// make "some" to say it has the item
some<V>(predicate: (v: T) => v is T & V): this is { guaranteedHas: V };
// make "find" to get the item if it has it
find<V>(this: { guaranteedHas: V }, predicate: (v: T) => v is T & V): V;
}
interface String {
// this is a "proper" typing, but...
includes<T, V extends string>(this: T, searchString: V): this is T & `${string}${V}${string}`;
}
function includes<D extends string>(d: D) {
// ...but you need a wrapper because `is` returns become booleans
return function inc<S extends string>(s: S): s is S & `${string}${D}${string}` {
return s.includes(d)
}
}
const list = ['a', 'b', '= c', 'd'] as const
if (list.some(includes('='))) {
const elementWithEqualSign = list.find(includes('='))
// ^?
// const elementWithEqualSign: "= c"
}
0赞
mbojko
9/20/2023
#3
为什么要用相同的测试遍历两次阵列?两者均可用于:find
const elementWithEqualSign = list.find(element => element.includes('='));
if (elementWithEqualSign) {
// elementWithEqualSign is a string here
}
评论
0赞
Ooker
9/20/2023
当我使用相同的想法但对于正则表达式字符串时,我被告知它的运行速度比 .因此,虽然您可以使用 result of 作为条件子句,但建议将它们分开。我在这里应用这个概念test()
match()
match
0赞
mbojko
9/20/2023
@Ooker 对于 VS ,性能差异似乎可以忽略不计:measurethat.net/Benchmarks/Show/12534/0/arrayfind-vs-arraysomefind
some
0赞
Ooker
9/20/2023
事情什么时候开始变得不可思议?因为如果它真的可以忽略不计,那么我们根本不需要使用,对吧?some()
评论