【问题标题】:How to dynamically add a new property while updating the draft on immer?如何在 immer 上更新草稿时动态添加新属性?
【发布时间】:2021-05-29 16:05:52
【问题描述】:

考虑以下代码,其中第 2 行以Property 'newProperty' does not exist on type 'WritableDraft<MyObject>'. TS7053 失败

// data is of type MyObject which until now has only a property myNumber
const payload = produce(data, (draft) => {    
  draft['newProperty'] = 'test';              // Property 'newProperty' does not exist on type 'WritableDraft<MyObject>'.  TS7053
});                                           

如何动态地向草稿添加新属性或将草稿的类型更改为已包含newProperty 的类型?我不想在MyObject 类型本身中有newProperty

【问题讨论】:

  • 这不是一个很好的解决方案,但你不能把它投给any吗?
  • 是的,这行得通,谢谢。但是我想知道是否有更好/官方的方法来做到这一点?
  • stackoverflow.com/questions/12710905/…,我很确定你可能想看看这个。如果您需要在 for 循环中添加任何新属性。这个问题实际上很常见,但所有解决方案似乎都违背了打字稿的最初目的。我不认为有一种真正优雅的方式来做到这一点。否则你只需要添加一个新属性作为参数的接口。
  • 你似乎想像一本简单的字典一样操作。问题当然是,之后您将如何处理该对象,它是否有意义(您在此处显示的代码之后不会为消费者提供任何好处,他们不知道它现在具有新属性,所以什么是你的最终目标)

标签: typescript immer.js


【解决方案1】:

您可以使用联合运算符向预先存在的类型添加新属性:&amp;。下面的代码应该可以解决您的问题。

(draft: WritableDraft<MyObject> & { newProperty : string }) => {
  // put the rest of your code here
}

编辑

查看 Linda Paiste 的回答后,我认为我上面采用的方法存在一些问题。我的回答确实为该类型添加了一个属性,它消除了您在访问或修改函数中的 newProperty 属性时会遇到的任何错误。但是,如果将来更改类型或变量名称,则会更加冗长且难以维护。此外,它会强制函数的调用者传入一个包含 newProperty 属性的对象,这可能不是您想要的。

【讨论】:

  • 我认为{newProperty: string} 应该进入&lt;&gt;,所以应该是WritableDraft&lt;MyObject &amp; { newProperty : string }&gt;
  • @ezhikov 你可能是对的,但我不知道,因为没有提供WritableDraft 的定义。
【解决方案2】:

只要不修改draft,就可以从produce 返回一个新对象。 returning new data from producers 上的文档显示了一个带有 switch 的示例,其中某些情况下会修改草稿,而其他情况下会返回新状态。只要您不在同一案例中同时进行这两种操作就可以了。

const payload = produce(data, (draft) => {
    return { ...draft, newProperty: "test" };
});

const n = payload.myNumber; // number
const s = payload.newProperty; // string

优点:

  • 不需要as 断言
  • payload 得到正确的类型 { newProperty: string; myNumber: number; }

缺点:

  • 实际上并未利用 Immer 的功能

Typescript Playground Link

【讨论】:

    【解决方案3】:

    如果你想在payload 上保留这个新类型,你必须在参数data 上强制转换新类型:

    let payload = produce(data as MyObject & { newProperty: string }, (draft) => {
      draft["newProperty"] = "test";
    })
    

    如果您不想在 payload 上保留您的类型,您可以在函数参数中或内部修改 draft 的类型:(draft as MyObject &amp; { newProperty: string })[newProperty] = "test"

    【讨论】:

      猜你喜欢
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      • 2021-07-17
      • 2014-04-06
      • 2014-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多