const a = {
b: 33,
c: [78, 99],
d:{e:{f:{g:true, h:{boom:'selecta'}}}}
} as const;
a.d.e.f.h.boom = 'respek'; //Cannot assign to 'boom' because it is a read-only property.ts(2540)
作为一个额外的好处,你可以使用这个技巧使嵌套函数的输入不可变:
type ImmutableObject<T> = {
readonly [K in keyof T]: Immutable<T[K]>;
}
export type Immutable<T> = {
readonly [K in keyof T]: T[K] extends Function ? T[K] : ImmutableObject<T[K]>;
}
所以才会发生这种事
const a = {
b: 33,
c: [78, 99],
d:{e:{f:{g:true, h:{boom:'selecta'}}}}
}
function mutateImmutable(input: Immutable<typeof a>) {
input.d.e.f.h.boom = 'respek'; //Cannot assign to 'boom' because it is a read-only property.ts(2540)
}
function freezer(obj) {
Object.getOwnPropertyNames(obj).forEach(name => {
if (typeof obj[name] == 'object' && obj[name] !== null)
freezer(obj[name]);
});
return Object.freeze(obj);
}
const a = freezer({
b:33,
c:[78, 99],
d:{e:{f:{g:true, h:{boom:'selecta'}}}}});
a.d.e.f.h.boom='respek'; // this does NOT throw an error. it simply does not override the value.
export class ClassicImmutableObject {
private readonly _stringProperty: string;
private readonly _numberProperty: number;
constructor(stringProperty: string, numberProperty: number) {
this._stringProperty = stringProperty;
this._numberProperty = numberProperty;
}
get stringProperty(): string {
return this._stringProperty;
}
get numberProperty(): number {
return this._numberProperty;
}
withStringProperty(stringProperty: string): ClassicImmutableObject {
return new ClassicImmutableObject(stringProperty, this._numberProperty);
}
withNumberProperty(numberProperty: number): ClassicImmutableObject {
return new ClassicImmutableObject(this._stringProperty, numberProperty);
}
}
你可以在代码中使用它:
import { ClassicImmutableObject } from './classic-immutable-object';
//...
immutableObjectExperiment(): string {
const immutableObject: ClassicImmutableObject =
new ClassicImmutableObject('test string', 123);
// this is not allowed: (TS2540 Can not assign to read-only property)
//immutableObject.stringProperty = 'modified';
let result = `Original classic immutable object: ${JSON.stringify(immutableObject)} \r\n`;
result += 'This demonstrates how to use getters:\r\n';
result += `stringProperty value: ${immutableObject.stringProperty}\r\n`;
result += `numberProperty value: ${immutableObject.numberProperty}\r\n\r\n`;
const modifiedImmutableObject: ClassicImmutableObject =
immutableObject.withStringProperty('modified test string');
result += `Modified classic immutable object with only stringProperty changed: ${JSON.stringify(modifiedImmutableObject)}\r\n`;
result += `Original immutable object is still available and unchanged: ${JSON.stringify(immutableObject)}`;
return result;
}
此函数的结果应为:
Original classic immutable object: {"_stringProperty":"test string","_numberProperty":123}
This demonstrates how to use getters:
stringProperty value: test string
numberProperty value: 123
Modified classic immutable object with only stringProperty changed: {"_stringProperty":"modified test string","_numberProperty":123}
Original immutable object is still available and unchanged: {"_stringProperty":"test string","_numberProperty":123}
const a= new class {
readonly b = 33,
readonly c:ReadonlyArray<number> = [78, 99],
readonly d = new class {
readonly e = new class {
readonly f = new class {
readonly g:true,
readonly h: new class {
readonly boom:'selecta'}}}};
6条答案
按热度按时间flvtvl501#
我们现在有了选项
as const
,这是@phil294提到的第一个选项(嵌套的readonly
)的语法简洁方式。作为一个额外的好处,你可以使用这个技巧使嵌套函数的输入不可变:
所以才会发生这种事
5n0oy7gb2#
如https://www.typescriptlang.org/docs/handbook/interfaces.html中所述,您可以在类/接口属性上使用
readonly
,或在不可变对象和数组上使用Readonly<...>
/ReadonlyArray<>
。在您的示例中,这看起来如下所示:显然,这是一个同义反复的语句,所以我建议你为你的对象定义合适的类结构。你并没有真正利用Typescript的任何特性,只是声明了一个嵌套的,无类型的对象。
但是如果你真的需要不使用类型定义,我认为唯一的方法是像Hampus建议的那样定义一个冷冻库(喜欢这个术语:D)。摘自MDN的
deepFreeze(obj)
函数:tl;dr:如果不定义类型,你就不能得到编译器类型错误。这就是Typescript的全部意义。
编辑:
这最后一个陈述是错误的。例如,
将抛出一个错误,因为类型被隐式设置为number。然而,对于readonly,我认为,你需要像上面定义的那样正确声明。
m1m5dgzv3#
Minko Gechev创建了DeepReadonly类型:
v440hwme4#
其他OOP语言默认具有类不变性,TypeScript也不例外。您可以使用经典的OO方式,如Java或PHP:
你可以在代码中使用它:
此函数的结果应为:
pxq42qpu5#
查看https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze或https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
冻结可能会做你想要的,但至少WebStorm不会警告你,当试图编辑对象和Chrome失败无声。
不能在冻结对象的属性集中添加或删除任何内容。任何这样做的尝试都将失败,可能是静默失败,也可能是抛出TypeError异常
zpjtge226#
这是可行的: