TypeScript 的 `readonly` 可以完全取代 Immutable.js 吗?

IT技术 reactjs typescript redux immutable.js
2021-05-12 03:33:23

我已经使用 React.js 完成了几个项目。他们中的一些人使用了 Flux,一些 Redux 和一些只是使用 Context 的普通 React 应用程序。

我真的很喜欢 Redux 使用函数式模式的方式。但是,开发人员很有可能无意中改变了状态。在寻找解决方案时,基本上只有一个答案——Immutable.js。老实说,我讨厌这个图书馆。它完全改变了您使用 JavaScript 的方式。此外,它必须在整个应用程序中实现,否则当一些对象是纯 JS 而一些是不可变结构时,你最终会遇到奇怪的错误。或者你开始使用.toJS(),这又 - 非常非常糟糕。

最近,我的一位同事建议使用 TypeScript。除了类型安全之外,它还有一个有趣的特性——您可以定义自己的数据结构,这些数据结构的所有字段都标记为readonly. 这样的结构基本上是不可变的。

我不是 Immutable.js 或 TypeScript 的专家。然而,在 Redux 存储中拥有不可变数据结构并且不使用 Immutable.js 的Promise似乎好得令人难以置信。TypeScript 是readonlyImmutable.js 的合适替代品吗?或者有什么隐藏的问题?

4个回答

虽然readonlyTypeScript修饰符确实只存在于设计类型中,并不影响运行时代码,但整个类型系统都是如此。也就是说,没有什么能阻止您在运行时将数字分配给类型为 的变量string所以这个答案有点像红鲱鱼……如果你在设计时被警告说你试图改变标记为constor 的东西readonly,那么这可能会消除大量运行时检查的需要。

readonly不足是有一个重要原因的有一个突出的问题readonly,这是当前(如TS3.4的),不同之处仅在它们的类型readonly属性是相互转让。这让您可以轻松突破readonly任何财产的保护壳并弄乱内脏:

type Person = { name: string, age: number }
type ReadonlyPerson = Readonly<Person>;

const readonlyPerson: ReadonlyPerson = { name: "Peter Pan", age: 12 };
readonlyPerson.age = 40; // error, "I won't grow up!"

const writablePerson: Person = readonlyPerson; // no error?!?!
writablePerson.age = 40; // no error!  Get a job, Peter.

console.log(readonlyPerson.age); // 40

这对readonly. 在此问题得到解决之前,您可能会发现自己同意之前的问题提交者,他最初将该问题命名为“只读修饰符是个笑话”🤡。

即使这确实得到解决,readonly也可能无法涵盖所有​​用例。您还需要遍历库(甚至标准库)中的所有接口和类型,并删除改变状态的方法。所以所有的用途Array都需要改为ReadonlyArray,所有的用途Map都需要改为ReadonlyMap等。一旦你这样做了,你就有了一种相当类型安全的方式来表示不变性。但这是很多工作。

无论如何,希望有所帮助;祝你好运!

的目的Immutable.js不是防止开发人员在编译时进行非法更改。它提供了一个方便的 API 来创建一个对象的副本,并更改​​其某些属性。使用 immutable.js 管理的对象获得类型安全性这一事实基本上只是使用它的副作用。

typescript“只是”一个打字系统。它没有实现Immutable.js制作不可变对象副本的任何功能在将变量声明为 时readonly它所做的只是在编译时检查您没有对其进行变异。如何设计代码来处理不变性不是类型系统的范围,您仍然需要一种处理它的方法。

React 通过提供方法setState而不是直接改变状态对象来确保不变性它负责为您合并更改的属性。但是,如果您例如使用 redux,您可能也需要一个方便的解决方案来处理不变性。这就是Immutable.js提供和typescript永远不会的东西,它与您是否喜欢 api 无关。

这有两个问题:

1)您必须一直使用readonly和/或诸如此类ReadonlyArray东西,这很容易出错。

2)readonly仅存在于编译时,而不是运行时,除非由不可变数据存储支持。一旦您的代码被转译为 JS,您的运行时代码就可以为所欲为。

结构共享相比,不可变 js 的区别readonly在于结构共享

这是一般的好处:想象一下嵌套的 JS 对象,它在多个嵌套级别上有 16 个属性。

随着readonly更新value的方式是复制旧的,修改我们想要的任何数据,然后我们有新的value!

随着JS更新value的方式是让所有没有改变,只复制那些没有(和他们的父母,我们,直到达到一个根目录)的属性。

因此,不可变 js 节省了更新时间(更少复制),节省了内存(更少复制),节省了决定我们是否需要重做一些相关工作的时间(例如,我们知道一些叶子没有改变,所以它们的 DOM 不必是被 React 改变了!)。

正如您所看到的,readonly它甚至与 Immutable js 不在一个联盟中。一是变异属性,二是高效的不可变数据结构库。