可以像这样创建DeepReadonly
类型:
type DeepReadonly<T> = {
readonly [P in keyof T]: DeepReadonly<T[P]>;
};
interface A {
B: { C: number; };
D: { E: number; }[];
}
const myDeepReadonlyObject: DeepReadonly<A> = {
B: { C: 1 },
D: [ { E: 2 } ],
}
myDeepReadonlyObject.B = { C: 2 }; // error :)
myDeepReadonlyObject.B.C = 2; // error :)
太棒了B
和B.C
都是只读的。当我尝试修改D
时...
// I'd like this to be an error
myDeepReadonlyObject.D[0] = { E: 3 }; // no error :(
我应该如何编写DeepReadonly
以使嵌套数组也是只读的?
9条答案
按热度按时间bgibtngc1#
从TypeScript 2.8开始,这现在是可能的,实际上是条件类型PR中的一个例子:https://github.com/Microsoft/TypeScript/pull/21316
另请参阅条件类型的类型推断注解:https://github.com/Microsoft/TypeScript/pull/21496
我稍微修改了这个例子,对只读数组值类型使用类型推断,因为我发现
(infer R)[]
比Array<T[number]>
更清楚,但这两种语法都有效。我还删除了示例NonFunctionPropertyNames
位,因为我想在输出中保留函数。这样做DeepReadonly也保留了可选字段(感谢Mariusz让我知道),例如:
虽然TS仍然有一些简单的方法来在某些场景中失去“readonly-ness”,但这是最接近C/C++风格的
const
值。qxsslcnc2#
除了zenmumbler answer之外,自从TypeScript 3.7发布以来,现在支持递归类型别名,它允许我们改进解决方案:
您可能注意到,我们没有像旧的解决方案那样扩展基本接口,比如
interface ImmutableArray<T> extends ReadonlyArray<Immutable<T>> {}
,而是直接引用它们,比如type ImmutableArray<T> = ReadonlyArray<Immutable<T>>
。旧的解决方案在大多数情况下都能很好地工作,但是由于替换了原始类型,所以几乎没有问题。例如,如果使用immer并将
ImmutableArray
的旧实现传递给produce
函数,则草案将缺少像push()
这样的数组方法。GitHub上也有issue,关于将DeepReadonly类型添加到TypeScript。
t30tvxxf3#
您可能需要使用ts-essentials包来实现此功能:
azpvetkf4#
我认为这是一个更好的解决方案:
flvtvl505#
DeepReadonly泛型是一个有价值的工具,可以帮助实现不可变性。
T extends ReadonlyArray<infer R> ?
对于Array<any>
和ReadonlyArray<any>
都为真。628mspwn6#
您可以使用只读数组:
但你不能在你的解决方案中使用它:
D
的类型是DeepReadonly<ReadonlyArray<{ E: number; }>>
,它不允许ReadonlyArray
启动。我怀疑你是否能成功地将其应用于包含数组的对象,如果你想要一个通用的接口/类型,而不是特定的,你可以对数组或对象进行深度读取。
例如,这将正常工作:
但是它有一个特定的接口(
A
),而不是通用的DeepReadonly
。另一种选择是使用Immutable.js,它带有一个内置的定义文件,非常容易使用。
r6hnlfcb7#
可以使用ts-toolbelt,它可以在任意深度对类型进行操作
在你的情况下,它将是:
如果您想深入计算它(出于显示目的),可以使用
Compute
来实现aydmsdu98#
unftdfkk9#
现在您可以只使用
as const
,因为它对所有嵌套对象都是只读的根据https://github.com/microsoft/TypeScript/issues/31856
下面是一个示例https://www.typescriptlang.org/play?#code/MYewdgzgLgBAhjAvDA3gKBpmY4FsCmAXDAIwA0GWcA5kapVljgceQ4-LcQEwUdYATOFDjEA2gF12AXzTT4EGKEhQ0auADoa+DUJEaADgFcIACwAUJAJQBuNJu0bm+JDADMdoA