如何在 JavaScript 中表示代数数据类型和模式匹配

2024-02-12

在像 OCaml 这样的函数式语言中,我们有模式匹配。例如,我想记录用户在我的网站上的操作。操作可以是 1) 访问网页,2) 删除项目,3) 检查其他用户的个人资料等。在 OCaml 中,我们可以编写如下内容:

type Action = 
  | VisitPage of string (* www.myweb.com/help *)
  | DeletePost of int (* an integer post id *)
  | ViewUser of string (* a username *)

但是,我不确定如何定义这个Action在 JavaScript 中。我能想到的一种方法是

var action_1 = { pageVisited: "www.myweb.com/help", postDeleted: null, userViewed: null }
var action_2 = { pageVisited: null, postDeleted: 12345, userViewed: null }
var action_3 = { pageVisited: null, postDeleted: null, userViewed: "SoftTimur" }

但这个结构并没有表达出pageVisited, postDeleted and userViewed其中是独一无二的。

有人能提出在 JavaScript 中更好地表示这种类型吗?

在 JavaScript 或 TypeScript 中是否存在进行模式匹配的通用方法?


你想要一个受歧视联盟 https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions,TypeScript 通过添加具有不同字符串文字值的公共属性来支持它,如下所示:

type VisitPage = { type: 'VisitPage', pageVisited: string }
type DeletePost = { type: 'DeletePost', postDeleted: number }
type ViewUser = { type: 'ViewUser', userViewed: string }

type Action = VisitPage | DeletePost | ViewUser

The Action类型是由type属性,TypeScript 将自动执行控制流分析以缩小范围Action当你检查它的时候type财产。这是获得模式匹配的方法:

function doSomething(action: Action) {
  switch (action.type) {
    case 'VisitPage':
      // action is narrowed to VisitPage
      console.log(action.pageVisited); //okay
      break;
    case 'DeletePost':
      // action is narrowed to DeletePost
      console.log(action.postDeleted); //okay
      break;
    case 'ViewUser':
      // action is narrowed to ViewUser
      console.log(action.userViewed); //okay
      break;
    default:
      // action is narrowed to never (bottom), 
      // or the following line will error
      const exhausivenessWitness: never = action; //okay
      throw new Error('not exhaustive');
  }
}

请注意,如果您愿意,您可以添加详尽检查,因此如果您向Actionunion,像上面这样的代码会给你一个编译时警告。

希望有帮助;祝你好运!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 JavaScript 中表示代数数据类型和模式匹配 的相关文章

随机推荐