Ocaml 未绑定记录字段id错误

Ocaml 未绑定记录字段id错误,ocaml,type-inference,reason,Ocaml,Type Inference,Reason,我正在尝试理性的反应。当我尝试向其中一个组件添加密钥时,我遇到了一个问题 我有一个TodoApp,它将TodoItem的列表作为状态。当我没有TodoItem的密钥时,应用程序工作正常。然而,当我添加它时,我得到了一个编译错误。我在此处添加文件以供参考: TodoItem.re: type item = { id: int, title: string, completed: bool }; let lastId = ref(0); let newItem = () =>

我正在尝试理性的反应。当我尝试向其中一个组件添加密钥时,我遇到了一个问题

我有一个TodoApp,它将TodoItem的列表作为状态。当我没有TodoItem的密钥时,应用程序工作正常。然而,当我添加它时,我得到了一个编译错误。我在此处添加文件以供参考:

TodoItem.re:

type item = {
  id: int,
  title: string,
  completed: bool
};

let lastId = ref(0);

let newItem = () => {
  lastId := lastId^ + 1;
  {id: lastId^, title: "Click a button", completed: false}
};

let toString = ReasonReact.stringToElement;

let component = ReasonReact.statelessComponent("TodoItem");

let make = (~item, children) => {
  ...component,
  render: (self) =>
    <div className="item">
      <input _type="checkbox" checked=(Js.Boolean.to_js_boolean(item.completed)) />
      (toString(item.title))
    </div>
};
类型项={
id:int,
标题:字符串,
已完成:布尔
};
设lastId=ref(0);
让newItem=()=>{
lastId:=lastId^+1;
{id:lastId^,标题:“单击按钮”,完成:false}
};
让toString=ReasonReact.stringToElement;
让component=ReasonReact.statelessComponent(“TodoItem”);
让make=(~item,children)=>{
…组件,
呈现:(自我)=>
(toString(项目名称))
};
TodoApp.re:

let toString = ReasonReact.stringToElement;

type state = {items: list(TodoItem.item)};

type action =
  | AddItem;

let component = ReasonReact.reducerComponent("TodoApp");

let currentItems = [TodoItem.{id: 0, title: "ToDo", completed: false}];

let make = (children) => {
  ...component,
  initialState: () => {items: currentItems},
  reducer: (action, {items}) =>
    switch action {
    | AddItem => ReasonReact.Update({items: [TodoItem.newItem(), ...items]})
    },
  render: ({state: {items}, reduce}) => {
    let numOfItems = List.length(items);
    <div className="app">
      <div className="title">
        (toString("What to do"))
        <button onClick=(reduce((_evt) => AddItem))> (toString("Add Something")) </button>
      </div>
      <div className="items">
        (
          ReasonReact.arrayToElement(
            Array.of_list(
              (List.map((item) => <TodoItem key=(string_of_int(item.id)) item />, items))
              /*List.map((item) => <TodoItem item />, items) This works but the above line of code with the key does not*/
            )
          )
        )
      </div>
      <div className="footer"> (toString(string_of_int(numOfItems) ++ " items")) </div>
    </div>
  }
};
让toString=ReasonReact.stringToElement;
类型状态={items:list(TodoItem.item)};
类型动作=
|附加项;
让组件=ReasonReact.reducerComponent(“TodoApp”);
让currentItems=[TodoItem.{id:0,标题:“ToDo”,完成:false}];
让make=(儿童)=>{
…组件,
initialState:()=>{items:currentItems},
reducer:(action,{items})=>
开关动作{
|AddItem=>ReasonReact.Update({items:[TodoItem.newItem(),…items]})
},
呈现:({state:{items},reduce})=>{
设numOfItems=List.length(items);
(toString(“做什么”))
AddItem()>(toString(“添加内容”))
(
ReasonReact.array元素(
表的数组(
(List.map((项)=>,项))
/*map((item)=>,items)这可以工作,但上面带有键的代码行不能工作*/
)
)
)
(toString(字符串,由int组成(numOfItems)+“items”))
}
};
我在出现错误的行附近添加了一条注释


错误显示为
未绑定记录字段id
,但我无法确定它是如何未绑定的。我在这里遗漏了什么?

不幸的是,在根据记录字段的使用情况从另一个模块推断记录类型时,类型推断有点有限,因此您需要给它一些帮助。两个可行的选择是:

注释
ìtem
的类型:

List.map((项:TodoItem.item)=>)
或本地打开使用记录字段的模块:

List.map((项)=>)

这实际上不是一个类型推断问题,而是一个范围问题(正如unbound value错误所说的那样)。记录文件与其他命名值一样,由其定义模块的名称限定,因此应使用以下语法访问:module.name。Open指令允许通过使用模块的命名值扩展当前范围来省略模块名和点。在这里,我猜想显式注释项的类型会在本地扩展范围,以便在其中添加TodoItem.item类型。@ghilesZ这确实有点道理,但我觉得奇怪(或者至少是不寻常的),范围会被限制为特定类型。这是可行的,但我不明白为什么。如果这是一个范围问题,它如何能够识别类型本身?类型本身不在范围之外吗?是否只有类型的属性超出范围?这似乎很奇怪,因为这意味着即使类型是推断的,我们也无法访问它的属性,除非明确声明?@leoOrion推断的类型是记录类型,而不是TodoItem.item类型。因为运算符“.”允许访问记录字段。剩下的问题是它是哪种记录类型?它有一个名为“id”的字段,应该在范围内。唯一的问题是这不在范围之内。