We will look at how we can use mapped types, conditional types, self-referencing types and the “infer” keyword to create a reusable generic type that traverses down the properties of an object and marks of all them as read-only. This is especially useful when used with Redux, to ensure our whole state tree is marked as read-only and immutable.
For example we have complex interface:
interface IRootState { userId: string; showCompletedOnly: boolean; todoTypes: string[]; todos: ITodo[]; iconGrid: string[][]; } interface IEmail { from: string; to: string[]; body: string; } interface ITodo { isCompleted: boolean; text: string; linkedEmail: IEmail; }
If we want to add readonly to all the props of IRootState. We want to do it automaticlly.
type DeepReadonlyObject<T> = { readonly [K in keyof T]: DeepReadonly<T[K]> }; type DeepReadonly<T> = T extends (infer E)[] ? ReadonlyArray<DeepReadonlyObject<E>> : T extends object ? DeepReadonlyObject<T> : T;
type IReadonlyRootState = DeepReadonly<IRootState>;