在 TypeScript 中表示可消耗的一次性对象

问题描述 投票:0回答:1

在 Rust 中,结构体可以有一个方法来获取结构体的所有权并移动它,使得以后再次使用该结构体是非法的,例如

struct Foo {}

impl Foo {
  fn consume(self) -> u32 {
    println!("consumed!");
    42
  }
}

fn main() {
  let x = Foo {};
  let val_1 = x.consume();
  let val_2 = x.consume(); // WON'T COMPILE
}

有没有办法使用 TypeScript 的类型系统来表示类似的状态变化?

typescript rust ownership linear-types
1个回答
0
投票

TypeScript 目前不支持子结构类型,例如线性/仿射类型,需要这些类型来表示您在此处尝试使用的所有权模型类型。在 microsoft/TypeScript#16148 上有一个长期开放的功能请求,被列为“等待更多反馈”,这意味着他们需要听到更多的社区需求,然后才能认真考虑实现它。而且这似乎还不够。如果您的用例令人信服的话,添加您的👍并描述您的用例不会“伤害”您,但它可能也没有帮助。

TypeScript 并没有真正对其类型系统中的任意状态变化进行建模。它只允许“缩小”,这意味着您最多可以对“
”做一些事情,这将使 TypeScript 将其视为更具体的类型。一般来说,更具体的类型比不太具体的类型具有

更多的功能,所以乍一看,这并不是一件容易做到的事情。您可以使用断言函数

x一直缩小到x.consume类型
,如果您调用它,
将会给您一个错误。但断言函数有一些警告:它们不能返回值(因此分配给
never
起不了多大作用)并且您需要显式的
类型注释。所以我能得到的最接近你想要的东西看起来像这样:
val_1
这里 class Foo { consume( ret: { value: number; } ): asserts this is { consume: never } { console.log("consumed!") ret.value = 42; } } const foo: Foo = new Foo(); const ret = { value: 0 }; foo.consume(ret); let val1 = ret.value; // ^? console.log(val1); // 42 foo.consume(ret); // ~~~~~~~ // error! This expression is not callable.

实例有一个
Foo
断言方法,该方法接受

consume()

 参数,该参数充当所需返回值的容器。如果您在 
ret
 的实例上调用 
consume()
(已明确注释为 
Foo
),那么它将改变 
Foo
 并缩小实例范围,以便 
ret
 属于 
consume
 类型并且它无法再次调用。
这实际上是否比仅仅放弃并以其他方式表示状态更好(例如,只需让 
never
 可多次调用,但在第一次后返回缓存的值等)取决于您的用例。我怀疑断言方法是否可行,但这确实超出了问题的范围。

Playground 代码链接


    

© www.soinside.com 2019 - 2024. All rights reserved.