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

Sof*_*mur 1 javascript ocaml object pattern-matching typescript

在像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 *)
Run Code Online (Sandbox Code Playgroud)

但是,我不确定如何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" }
Run Code Online (Sandbox Code Playgroud)

但是这种结构并没有表达出来pageVisited,postDeleted并且userViewed在它们中是排他性的.

任何人都可以在JavaScript中提出更好的代表吗?

有没有在JavaScript或TypeScript中进行模式匹配的常用方法?

jca*_*alz 7

你想要一个有区别的联合,TypeScript支持通过添加一个具有不同字符串文字值的公共属性,如下所示:

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

type Action = VisitPage | DeletePost | ViewUser
Run Code Online (Sandbox Code Playgroud)

Action类型由判别type属性,和打字原稿将自动执行控制流分析,以缩小的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');
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您愿意,可以添加详尽的检查,因此,如果您要向Action联合添加其他类型,则上述代码将为您提供编译时警告.

希望有所帮助; 祝好运!


Der*_*會功夫 5

函数式编程中的类型可以用类来模拟:

class Action {}
class VisitPage extends Action {
    constructor(pageUrl){
        super();
        this.pageUrl = pageUrl;
    }
}
class ViewUser extends Action {
    constructor(userName){
        super();
        this.userName = userName;
    }
}

var myAction = new VisitPage("http://www.google.com");
console.log(myAction instanceof Action);
console.log(myAction.pageUrl);
Run Code Online (Sandbox Code Playgroud)

对于模式匹配:

class Action {}
class VisitPage extends Action {
    constructor(pageUrl){
        super();
        this.pageUrl = pageUrl;
    }
}
class ViewUser extends Action {
    constructor(userName){
        super();
        this.userName = userName;
    }
}

function computeStuff(action){
    switch(action.constructor){
        case VisitPage:
            console.log(action.pageUrl); break;
        case ViewUser:
            console.log(action.userName); break;
        default:
            throw new TypeError("Wrong type");
    }
}

var action = new ViewUser("user_name");
var result = computeStuff(action);
Run Code Online (Sandbox Code Playgroud)