英文:
Delete optional property after type predicate check while maintaining static analysis
问题
我有一个只有可选属性的接口 I
。在我的情况下,I
是一个泛型。我需要一个类型缩小函数,仍然允许删除缩小的属性。以下是代码示例:
interface I {
value?: number
}
function check(i: I): i is I & { value: number } {
return "value" in i
}
function test(i: I) {
if (check(i)) {
i.value += 1 // 可行
delete i.value // 错误:'delete' 运算符的操作数必须是可选的。
}
}
// i as I is not an option to force deletion because it allows the access
// to i.value after deletion
function test2(i: I) {
if (check(i)) {
i.value += 1 // 可行
delete (i as I).value // 可行
i.value += 1 // 仍然可行
}
}
// 期望的行为应该类似于
function test(v: I) {
if ("value" in v) {
v.value += 5 // 可行
delete v.value // 可行
v.value += 5 // 错误:易理解且良好
}
}
问题在于,缩小类型会创建一个新的带有 value
作为必需类型的接口。因此,我需要一种语法来表示 value
可以是可选的/可删除的,但当前包含一个值。
一种解决方法是定义一个用于删除的函数,该函数将值重新缩小为可选。目前没有直接支持 delete
关键字的语法或模式,可以实现这一目标。
英文:
I have an interface I
with only optional properties. In my case I
is a generic. I need a type narrowing function that still allows to delete
the narrowed property. The following code shows the problem.
interface I {
value?: number
}
function check(i: I): i is I & { value: number } {
return "value" in i
}
function test(i: I) {
if (check(i)) {
i.value += 1 // ok
delete i.value // error: The operand of a 'delete' operator must be optional.
}
}
// i as I is not an option to force deletion because it allows the access
// to i.value after deletion
function test2(i: I) {
if (check(i)) {
i.value += 1 // ok
delete (i as I).value // ok
i.value += 1 // !!! still ok
}
}
// expected behaviour should be something like
function test(v: I) {
if ("value" in v) {
v.value += 5 // ok
delete v.value // ok
v.value += 5 // error: understandable and good
}
}
The problem is, that the narrowing creates a new interface with value
as a required type. So I need syntax to say that value
can be optional / removed but currently contains a value.
A workaround would be to define a function for deleting that renarrows the value back to optional.
Is there some syntax or pattern to allow the use of the delete
keyword?
答案1
得分: 1
以下是您要翻译的内容:
很不幸,您无法通过其返回类型为i is X
形式的自定义类型守卫函数来表达您正在进行的操作,其中X是某种类型。 TypeScript没有一种类型可以表示“类型为number
的value
属性是可选的(因此可以被delete
),但已知存在(因此可以分配给number
)”。类型{value?: number}
表示该属性是可选的但可能缺失,而类型{value: number}
表示该属性已知存在但是必需的。这两者都不适合用作自定义类型守卫函数的返回类型。
通过控制流分析,您可以实现所需的状态,正如您所看到的(尽管我会更改您的示例为:
function test(i: I) {
if (typeof i.value !== "undefined") {
i.value += 5 // ok
delete i.value // ok
i.value += 5 // error: understandable and good
}
}
而不是if ("value" in i)
)。但再次强调,没有适当的方法来表示通过检查后的状态为i
赋予一个新的类型。
我没有找到相关的TypeScript GitHub问题;所以您可能想要提交一个新的功能请求,以获取以这种方式工作的类型。但我怀疑它会被实现,因为这不是一个非常常见的情况,而解决方法是使用直接的类型守卫而不是自定义类型守卫函数。如果您决定提交功能请求,您应该小心地说明为什么现有的解决方法不够。
英文:
Unfortunately you can't express what you're doing with a custom type guard function whose return type is of the form i is X
for some type X
. TypeScript doesn't have a type that means "the value
property of type number
is optional (so it may be delete
d), but known to be present (so it can assigned to number
)". The type {value?: number}
means the property is optional but possibly missing, and the type {value: number}
means the property is known to be present but is required. Neither is appropriate for the return type of a custom type guard function.
The desired state is possible to achieve via control flow anlysis as you've seen (although I'd change your example to
function test(i: I) {
if (typeof i.value !== "undefined") {
i.value += 5 // ok
delete i.value // ok
i.value += 5 // error: understandable and good
}
}
instead of if ("value" in i)
). But again, there's no appropriate way to represent that post-checked state as giving i
a new type.
I didn't find a relevant TypeScript GitHub issue; so you might want to file a new feature request for a type that works this way. But I doubt it would be implemented, since it's not a very common situation, and the workaround is to use the direct type guard instead of a custom type guard function. If you do decide to file a feature request, you should take care to demonstrate why available workarounds don't suffice.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论