TypeScript 为不可变类型添加约束

bqjvbblv  于 4个月前  发布在  TypeScript
关注(0)|答案(7)|浏览(149)
say, i have a通用函数,设计上要求其参数只能接受不可变的参数,我希望我能从TS中得到这样的保证,通过声明我的函数如下:

function doThings(value: T): Result {
// ...
}


至于如何使接口不可变:

readonly interface Point {
readonly x: number;
readonly y: number;
}


所以这里要解决的问题是确保调用者在将参数传递给函数后不会改变它

**简单用例** :基于哈希的数据容器,它计算给定值的哈希值,并将其存储在该哈希值处,这一切都会正常工作,直到值在外部被改变,存储的哈希值不再有效,因此容器实际上不再起作用
**另一个用例** :缓存或对象池或其他任何涉及多方共同持有同一对象的情况,必须保证该对象不被一方修改,以防止所有其他方出现幽灵般的动作
m528fe3b

m528fe3b1#

Readonly<T> 应该给你一个浅层的只读支持。对于深层次的只读,#10725 已经跟踪添加了。

xqkwcwgp

xqkwcwgp2#

我正在谈论特殊的泛型约束,这将保证类型参数是不可变的。
你对 Readonly 是什么意思?

interface Writable {
    value: string;
}
function willOnlyTakeReadonly<T>(data: Readonly<T>): void {
}
declare const writable: Writable ;
willOnlyTakeReadonly(writable); // <-- no problem

我担心它在最新的 TypeScript 版本中不起作用,因为任何东西都可以代替 Readonly<T> 参数 包括具有所有可写属性的接口

w8rqjzmb

w8rqjzmb3#

你不能改变输入,尽管

type Writable = {
  value: string
}

function willOnlyTakeReadonly(data: Readonly<Writable>): void {
  data.value = 'a' // error Cannot assign to 'value' because it is a constant or a read-only property
}

declare const writable: Writable

willOnlyTakeReadonly(writable)
mctunoxg

mctunoxg4#

我不确定我是否理解,你对输入有什么限制?

bvn4nwqk

bvn4nwqk5#

我添加了两个用例,以便了解何时/为何限制输入是有用的。

1wnzp6jl

1wnzp6jl6#

它为什么被关闭了?

83qze16e

83qze16e7#

我支持这个提案的目标。一些设计问题:

  1. 对于Assert对象不可变的接口修饰符,重载 readonly 关键字非常令人困惑(它看起来已经让 mhegazy 感到困惑了)。理想情况下,我们应该使用 immutable,尽管我不知道是否有关于添加新保留字的担忧。(我在后面的评论中将使用 immutable。)
  2. 什么阻止了一个包含相同成员但没有 readonly 修饰符的接口在结构上被分配给上面声明的 Point 接口?类型 immutable 的修饰符是否是可分配性的另一个检查点?
  3. 用户可能希望有同一接口的可变、只读和不可变版本。当前的只读(Support readonly type operator to allow correct definition of Object.freeze  #10725 / Strict variance and read-only versions of types #18770)提案是用户定义一个可变接口 Point 并为深度只读版本编写 readonly Point(也许“深度只读”一词在某些情况下需要自定义)。类似地,我想为深度不可变接口编写 immutable Point。本质上,immutable 操作符应该声明构成对象抽象状态的一部分字段本身为 immutable;这些是与接口一起变为 readonly 的相同字段。immutable 接口具有与 readonly 接口相同的方法。给定这样一个操作符,原始示例可以写成:
function doThings<T>(value: immutable T): Result<T> {
   // ...
}

但此外,具有 immutable 类型参数约束可能对用户更清晰,或者根据类型参数推断的工作方式使实现更容易(哎呀)。

  1. 用户如何生成 immutable 对象?一种方法总是类型Assert,或者使用反射来查找它应该递归 deepFreeze 的字段并Assert结果为 immutable 的方法。我们还可以考虑从现有不可变部分构造单个新不可变对象的方法,例如:
immutable {a: 1, b: 2}
immutable [3, 4, 5]
immutable new MyPair(point1, point2)

要使用相同的构造函数构造可变和不可变对象,我们需要使其在新的物体是否可变方面具有多态性。也就是说,我们认为调用上的 immutable 修饰符的存在或缺失是一个构造函数的泛型参数,并且在整个构造函数的签名和主体中,owned 类型修饰符引用此参数。然后编译器检查每个字段赋值以确保如果新对象是不可变的,则正在分配的引用也是不可变的。(有人知道这在其他编程语言中的先例吗?我可以自己研究,但我已经花了足够的时间在这个上了。)

相关问题