import { IfNoDeepValue } from './helpers.js'; import { Or } from './logical.js'; import { IfEquals, IfNever, IfTuple } from './type-check.js'; /** * Marks given keys as readonly */ export type ReadonlySome = Readonly> & Omit; /** * Make all properties in T readonly deeply */ export type DeepReadonly = { readonly [ K in keyof T as IfNever, never, K> ]: IfNoDeepValue> extends true // Do not deep process No-Deep values ? T[K] : // Deep process objects DeepReadonly>; }; /** * Make all properties in T readonly deeply */ export type DeeperReadonly = { readonly [ K in keyof T as IfNever, never, K> ]: IfTuple> extends true // Deep process tuples positionally ? readonly [...DeeperReadonlyTuple>] : NonNullable extends readonly (infer U)[] // Deep process arrays ? null extends T[K] // Preserve a `| null` member lost by NonNullable above ? readonly DeeperReadonly[] | null // Always readonly - that is DeeperReadonly's whole purpose : readonly DeeperReadonly[] : // Do not deep process No-Deep values IfNoDeepValue> extends true ? T[K] : // Deep process objects DeeperReadonly>; }; type DeeperReadonlyTuple = T extends readonly [infer Head, ...infer Rest] ? [ IfNoDeepValue> extends true ? Head : DeeperReadonly>, ...DeeperReadonlyTuple, ] : []; /** * Returns readonly keys of an object */ export type ReadonlyKeys = keyof PickReadonly; /** * Pick all readonly properties in T */ export type PickReadonly = { [ K in keyof T as Or< // Omit never keys IfNever>, // Omit required IfEquals<{ [Q in K]: T[K] }, { readonly [Q in K]: T[K] }, false, true> > extends true ? never : K ]: T[K]; }; /** * Omit all readonly properties in T */ export type OmitReadonly = { [ K in keyof T as Or< // Omit never keys IfNever>, // Omit required IfEquals<{ [Q in K]: T[K] }, { readonly [Q in K]: T[K] }> > extends true ? never : K ]: T[K]; }; /** * Pick all readonly properties in T deeply */ export type DeepPickReadonly = { [ K in keyof T as Or< // Omit never keys IfNever>, // Omit required IfEquals<{ [Q in K]: T[K] }, { readonly [Q in K]: T[K] }, false, true> > extends true ? never : K ]: IfNoDeepValue> extends true // Do not deep process No-Deep values ? T[K] : // Deep process objects (Exclude, not NonNullable - preserves a `| null` member) DeepPickReadonly>; }; /** * Pick all readonly properties in T deeply */ export type DeepOmitReadonly = { [ K in keyof T as Or< // Omit never keys IfNever>, // Omit required IfEquals<{ [Q in K]: T[K] }, { readonly [Q in K]: T[K] }> > extends true ? never : K ]: IfNoDeepValue> extends true // Do not deep process No-Deep values ? T[K] : // Deep process objects (Exclude, not NonNullable - preserves a `| null` member) DeepOmitReadonly>; }; /** * Pick all readonly properties in T deeply including arrays */ export type DeeperPickReadonly = { [ K in keyof T as Or< // Omit never keys IfNever>, // Omit required IfEquals<{ [Q in K]: T[K] }, { readonly [Q in K]: T[K] }, false, true> > extends true ? never : K ]: IfTuple> extends true // Deep process tuples positionally ? DeeperPickReadonlyTuple> : NonNullable extends readonly (infer U)[] // Deep process arrays ? NonNullable extends any[] ? // was mutable - DeeperPickReadonly doesn't touch mutability, unlike DeeperReadonly null extends T[K] ? DeeperPickReadonly[] | null : DeeperPickReadonly[] : null extends T[K] // was readonly - preserve that ? readonly DeeperPickReadonly[] | null : readonly DeeperPickReadonly[] : // Do not deep process No-Deep values IfNoDeepValue> extends true ? T[K] : // Deep process objects (Exclude, not NonNullable - preserves a `| null` member) DeeperPickReadonly>; }; type DeeperPickReadonlyTuple = T extends readonly [infer Head, ...infer Rest] ? [ IfNoDeepValue> extends true ? Head : DeeperPickReadonly>, ...DeeperPickReadonlyTuple, ] : []; /** * Pick all readonly properties in T deeply including arrays */ export type DeeperOmitReadonly = { [ K in keyof T as Or< // Omit never keys IfNever>, // Omit required IfEquals<{ [Q in K]: T[K] }, { readonly [Q in K]: T[K] }> > extends true ? never : K ]: IfTuple> extends true // Deep process tuples positionally ? DeeperOmitReadonlyTuple> : NonNullable extends readonly (infer U)[] // Deep process arrays ? NonNullable extends any[] ? // was mutable - DeeperOmitReadonly doesn't touch mutability, unlike DeeperReadonly null extends T[K] ? DeeperOmitReadonly[] | null : DeeperOmitReadonly[] : null extends T[K] // was readonly - preserve that ? readonly DeeperOmitReadonly[] | null : readonly DeeperOmitReadonly[] : // Do not deep process No-Deep values IfNoDeepValue> extends true ? T[K] : // Deep process objects (Exclude, not NonNullable - preserves a `| null` member) DeeperOmitReadonly>; }; type DeeperOmitReadonlyTuple = T extends readonly [infer Head, ...infer Rest] ? [ IfNoDeepValue> extends true ? Head : DeeperOmitReadonly>, ...DeeperOmitReadonlyTuple, ] : [];