You can use ts-toolbelt, it can do operations on types at any depth
In your case, it would be:
import {O} from 'ts-toolbelt'
interface A {
B: { C: number; };
D: { E: number; }[];
}
type optional = O.Readonly
And if you want to compute it deeply (for display purposes), you can use Compute
for that