TypeScript 添加会话类型

p5cysglq  于 9个月前  发布在  TypeScript
关注(0)|答案(3)|浏览(147)

搜索词

会话类型,可变类型,有状态类型

建议

会话类型用于描述有状态协议(即会话)。静态类型检查可以防止因调用方法顺序错误而造成的失误。这对于提供公共API以引导用户尤其有帮助。
一个简单的例子是一个需要认证的API:首先,你需要调用一个 login 方法,然后你才被允许调用其他方法,例如 getPrivateData
会话类型在类型系统中仍然是一个相对模糊的功能。据我所知,没有主要的编程语言默认支持它。因此,Typescript可能是其中的创新者;)有很多学术材料,但恐怕没有面向公众的材料。这似乎是一篇相当易读的介绍: http://www.simonjf.com/2016/05/28/session-type-implementations.html

用例

会话类型的最常见用例是有状态连接协议(即会话)。例如,处理文件访问的类,它将确保在写入文件之前打开文件。
目前,这些用例要么由运行时检查覆盖,要么由“流畅API”的设计实现。然而,这两种解决方案都不充分:
运行时检查等同于动态类型,可能在重构时被遗漏。它们无法静态分析以提供IDE支持。
使用流畅API,你会失去许多通用语言能力,如返回值、控制流等。如果流畅API实现为“单类型”,则完全没有类型检查,必须通过RuntimeExceptions进行类型检查。
当实现“类型化的流畅API”(即返回与 this 不同的对象),可能会变得浪费资源,因为许多对象没有理由被创建,而且代码也会变得相当复杂。

示例

对扑克游戏(德州扑克)进行建模:

  1. const pokerGame = new PokerGame();
  2. await pokerGame.receiveCards();
  3. const cards = pokerGame.getMyCards();
  4. if(ai.iWantToBet()){
  5. await pokerGame.bet() // may only be called once and is exclusive with .pass(), .fold()
  6. }else if(ai.iWantToPass()){
  7. await pokerGame.pass() // may only be called once and is exclusive with .bet(), .fold()
  8. }else if(ai.iWantToFold()){
  9. await pokerGame.fold() // may only be called once and is exclusive with .bet(), .pass()
  10. }
  11. await pokerGame.nextRound() // only method which is allowed to be called by now.
  12. const publicCards = pokerGame.getPublicCards(); // can only be called after nextRound() has been called
  13. // and so on...

作为语法,我们可以使用类型Assert语法( x as Type ),因为这基本上与在函数调用中设置 this 的类型相同。
也许有人可以将语法扩展到设置参数的类型,但我将其留给大家讨论..

  1. interface RoundFinished {
  2. nextRound();
  3. }
  4. interface RoundStart {
  5. bet(): this as RoundFinished;
  6. pass(): this as RoundFinished;
  7. fold(): this as GameFinished;
  8. }
  9. interface GameFinished {
  10. getResults();
  11. }
  12. class PokerGame {
  13. bet(): this as RoundFinished {
  14. // code
  15. // after the function exits, "this" is now typechecked as "RoundFinished" (without having to use "fluent API")
  16. }
  17. nextRound(): this as RoundStart {
  18. // and so on..
  19. }
  20. }

检查清单

我的建议满足以下准则:

  • 这不会对现有的TypeScript/JavaScript代码造成破坏性更改
  • 这不会改变现有JavaScript代码的运行时行为
  • 这可以在不根据表达式的类型生成不同JS的情况下实现
  • 这不是一个运行时特性(例如库功能、JavaScript输出非ECMAScript语法等)
  • 这个特性将与其他 TypeScript's Design Goals 一致。
pbgvytdp

pbgvytdp1#

这实际上已经相当支持了,使用Assert语法。

$x_1a^0b^1x$

sgtfey8w

sgtfey8w2#

Assert方法只能缩小,对吧?你不能用它们来扩大或修改类型。所以任何具有 obj.prop 状态的类型在调用 obj.turnPropIntoANumber() 之后开始时是 string,但结束时是 number,这不是我们可以在 TS 中建模的东西。

oug3syen

oug3syen3#

我认为最小的改变就是允许将Assert和函数/方法的返回类型组合在一起,例如 "(Assert this 是 AnotherType) & 返回类型"。

相关问题