在Typescript中建议Object.freeze
还是有其他方法可以确保对象保持不变?
由于const
仅保护实例,而不保护属性,因此这显然不是我正在寻找的答案。
答案 0 :(得分:10)
还有其他方法可以确保对象保持不变吗?
这取决于您想要的保险水平。
如果您想确保没有消费者,无论是TypeScript还是JavaScript代码,都可以在运行时修改对象属性,Object.freeze
就是这样做的。
如果编译时检查已足够,例如当所有使用者代码都保证仅限TypeScript并进行类型检查时,您可以使用ReadOnly
generic type,它采用对象类型并生成所有properties readonly
。事实上,Object.freeze()
在library type definitions中声明为返回ReadOnly
- 其参数的修改类型:
freeze<T>(o: T): Readonly<T>;
对于seal
,无法在类型系统中表示密封对象,Object.seal()
为declared to return the same type it receives:
seal<T>(o: T): T;
和Object.seal()
是唯一的出路。
答案 1 :(得分:1)
as const
这代表了在所有级别的对象或数组中的不变性的严重冻结。
const a = {
b: 1,
c: {d: 'e'},
f: ['g', 'h'],
} as const
这些都不允许覆盖
a = 'not'
a.b = 'going'
a.c.d = 'to'
a.f[1] = 'change'
All result in error "TS2540: Cannot assign to '<name>' because it is a read-only property."
注意:自定义对象可能不是完全不变的,具体取决于您的实现。
奖金:如果用作枚举替换,则可以添加此行
type a = typeof a[keyof typeof a]
Immutable<>
的不可变参数此操作与as const
相同,以深度冻结参数
// Add this and make it reuseable
type Immutable<T> = {
readonly [K in keyof T]: Immutable<T[K]>
}
在<>
中定义类型,即Immutable<MyType>
_method = (a: Immutable<{b:{c:{d:[string]}}}>) => {
// This will complain
a.b.c.d[0] = ""
}
答案 2 :(得分:0)
如果需要运行时检查和编译时检查,
export const frozen:Readonly<{a:number}> = Object.freeze({a:1});
但是,以下内容已经给我带来TypeError:无法分配为只读属性
export const frozen = Object.freeze({a:1});
答案 3 :(得分:0)
在对象和函数上递归添加只读类型的Object.freeze():
export const deepFreeze = <T>(source: T, freezeParent = true): DRo<T> => {
if (freezeParent) Object.freeze(source)
Object.getOwnPropertyNames(source).forEach(function(prop) {
if (
Object.prototype.hasOwnProperty.call(source as any, prop) &&
(source as any)[prop] !== null &&
(typeof (source as any)[prop] === 'object' || typeof (source as any)[prop] === 'function')
) {
if (Object.isFrozen((source as any)[prop])) {
deepFreeze((source as any)[prop], false)
} else {
deepFreeze((source as any)[prop], true)
}
}
})
return source as DRo<T>
}
type DRo<T> = T extends (infer R)[] ? DRoArr<R> : T extends Function ? T : T extends object ? DRoObj<T> : T
interface DRoArr<T> extends ReadonlyArray<DRo<T>> {}
type DRoObj<T> = {
readonly [P in keyof T]: DRo<T[P]>
}
Object.freeze包含Seal。