It is possible to create a DeepReadonly type like this:
type DeepReadonly = {
readonly [P in keyof T]: DeepReadonly;
};
As of TypeScript 2.8, this is now possible and actually an example in the PR for Conditional Types: https://github.com/Microsoft/TypeScript/pull/21316
Also see the notes on type inference for Conditional Types: https://github.com/Microsoft/TypeScript/pull/21496
I modified the example slightly to use the type inference for the readonly array value type because I find (infer R)[] clearer than Array but both syntaxes work. I also removed the example NonFunctionPropertyNames bit as I want to preserve functions in my output.
type DeepReadonly =
T extends (infer R)[] ? DeepReadonlyArray :
T extends Function ? T :
T extends object ? DeepReadonlyObject :
T;
interface DeepReadonlyArray extends ReadonlyArray> {}
type DeepReadonlyObject = {
readonly [P in keyof T]: DeepReadonly;
};
Doing DeepReadonly this way also preserves optional fields (thanks to Mariusz for letting me know), e.g.:
interface A {
x?: number;
y: number;
}
type RA = DeepReadonly;
// RA is effectively typed as such:
interface RA {
readonly x?: number;
readonly y: number;
}
While TS still has some easy ways to lose "readonly-ness" in certain scenarios, this is as close to a C/C++ style const value as you will get.