@rimbu/deep
Version:
Tools to use handle plain JS objects as immutable objects
31 lines (29 loc) • 1.42 kB
text/typescript
import type { IsAny, IsPlainObj } from '@rimbu/base';
/**
* A deep readonly typed version of given type T. Makes all properties or elements read only.
* It maps types using the following rules:
* - arrays and tuples become readonly counterparts, and all element types are wrapped in `Protected` if applicable
* - Maps of key type K and value type V become Maps of key type `Protected<K>` and value type `Protected<V>`
* - Sets of element type E become Sets of element type `Protected<E>`
* - Promises of value type E become Promises of value type `Protected<E>`
* - Objects that have only simple properties (no functions or iterators) will have all the properties as Protected if applicable
* - Any other type will not be mapped
* @typeparam T - the input type
*/
export type Protected<T> = IsAny<T> extends true
? // to prevent infinite recursion, any will be any
T
: T extends readonly any[] & infer A
? // convert all keys to readonly and all values to `Protected`
{ readonly [K in keyof A]: Protected<A[K]> }
: T extends Map<infer K, infer V>
? ReadonlyMap<Protected<K>, Protected<V>>
: T extends Set<infer E>
? ReadonlySet<Protected<E>>
: T extends Promise<infer E>
? Promise<Protected<E>>
: IsPlainObj<T> extends true
? // convert all keys to readonly and all values to `Protected`
{ readonly [K in keyof T]: Protected<T[K]> }
: // nothing to do, just return `T`
T;