As described in https://www.typescriptlang.org/docs/handbook/interfaces.html, you can use readonly
on class/interface properties or Readonly<...>
/ReadonlyArray<>
for immutable objects and arrays. In your case, this would look like the following:
const a: Readonly<{
b: number,
c: ReadonlyArray<number>,
d: Readonly<{
e: Readonly<{
f: Readonly<{
g: boolean,
h: Readonly<{
boom: string
}>
}>
}>
}>
}> = {
b: 33,
c: [78, 99],
d:{e:{f:{g:true, h:{boom:'selecta'}}}}
}
a.d.e.f.h.boom = 'respek'; // error: Cannot assign to 'boom' because it is a constant or a read-only property.
Obviously, this is quite the tautological statement, so I suggest you define proper class structure for your object. You are not really taking advantage of any of Typescript's features by just declaring a nested, untyped object.
But if you really need to go without type definitions, I think the only way is defining a freezer (love the term :D) like Hampus suggested. Taken from deepFreeze(obj)
function from MDN:
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.
tl;dr: You cannot get compiler type errors without defining types. That is the whole point of Typescript.
edit:
this very last statement is wrong. For example,
let a = 1
a = "hello"
will throw an error because the type is implicitly set to number. For readonly however, I think, you will need proper declaration as defined above.