Is it possible to transform a typescript object type deeply writable, but also remove readonly
type operator from array types?
Similar to this, but - as I mentioned - also remove readonly
from array types.
// if initial type is:
interface InitialType {
readonly field: string;
readonly array: readonly { readonly arraySubfield: string; }[];
readonly obj: {
readonly objSubfield1: string;
readonly objSubfield2: readonly string[];
};
}
// then the result type would be:
interface ResultType {
field: string;
array: { arraySubfield: string }[];
obj: {
objSubfield1: string;
objSubfield2: string[];
};
}
// achieved by doing this:
type ResultType = Writable<InitialType>;
CodePudding user response:
Here ya go, a deep writable type that handles way too many things:
type Writable<T> =
// check for things that are objects but don't need changing
T extends ((...args: any[]) => any) | Date | RegExp
? T
: T extends ReadonlyMap<infer K, infer V> // maps
? Map<Writable<K>, Writable<V>> // make key and values writable
: T extends ReadonlySet<infer U> // sets
? Set<Writable<U>> // make elements writable
: T extends ReadonlyArray<unknown> // is an array or tuple?
? `${bigint}` extends `${keyof T & any}` // is tuple
? { -readonly [K in keyof T]: Writable<T[K]> }
: Writable<T[number]>[] // is regular array
: T extends object // is regular object
? { -readonly [K in keyof T]: Writable<T[K]> }
: T; // is primitive or literal value
Essentially it's this:
type Writable<T> = T extends object ? { -readonly [K in keyof T]: Writable<T[K]> } : T;
but it handles a lot more things correctly. Things like (and only) arrays dates, functions, regex, maps, sets, tuples, readonly maps, and readonly sets.