UNPKG

3 kBTypeScriptView Raw
1import type {BuiltIns, HasMultipleCallSignatures} from './internal';
2
3/**
4Convert `object`s, `Map`s, `Set`s, and `Array`s and all of their keys/elements into immutable structures recursively.
5
6This is useful when a deeply nested structure needs to be exposed as completely immutable, for example, an imported JSON module or when receiving an API response that is passed around.
7
8Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/13923) if you want to have this type as a built-in in TypeScript.
9
10@example
11```
12// data.json
13{
14 "foo": ["bar"]
15}
16
17// main.ts
18import type {ReadonlyDeep} from 'type-fest';
19import dataJson = require('./data.json');
20
21const data: ReadonlyDeep<typeof dataJson> = dataJson;
22
23export default data;
24
25// test.ts
26import data from './main';
27
28data.foo.push('bar');
29//=> error TS2339: Property 'push' does not exist on type 'readonly string[]'
30```
31
32Note that types containing overloaded functions are not made deeply readonly due to a [TypeScript limitation](https://github.com/microsoft/TypeScript/issues/29732).
33
34@category Object
35@category Array
36@category Set
37@category Map
38*/
39export type ReadonlyDeep<T> = T extends BuiltIns
40 ? T
41 : T extends new (...arguments_: any[]) => unknown
42 ? T // Skip class constructors
43 : T extends (...arguments_: any[]) => unknown
44 ? {} extends ReadonlyObjectDeep<T>
45 ? T
46 : HasMultipleCallSignatures<T> extends true
47 ? T
48 : ((...arguments_: Parameters<T>) => ReturnType<T>) & ReadonlyObjectDeep<T>
49 : T extends Readonly<ReadonlyMap<infer KeyType, infer ValueType>>
50 ? ReadonlyMapDeep<KeyType, ValueType>
51 : T extends Readonly<ReadonlySet<infer ItemType>>
52 ? ReadonlySetDeep<ItemType>
53 : // Identify tuples to avoid converting them to arrays inadvertently; special case `readonly [...never[]]`, as it emerges undesirably from recursive invocations of ReadonlyDeep below.
54 T extends readonly [] | readonly [...never[]]
55 ? readonly []
56 : T extends readonly [infer U, ...infer V]
57 ? readonly [ReadonlyDeep<U>, ...ReadonlyDeep<V>]
58 : T extends readonly [...infer U, infer V]
59 ? readonly [...ReadonlyDeep<U>, ReadonlyDeep<V>]
60 : T extends ReadonlyArray<infer ItemType>
61 ? ReadonlyArray<ReadonlyDeep<ItemType>>
62 : T extends object
63 ? ReadonlyObjectDeep<T>
64 : unknown;
65
66/**
67Same as `ReadonlyDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `ReadonlyDeep`.
68*/
69type ReadonlyMapDeep<KeyType, ValueType> = {} & Readonly<ReadonlyMap<ReadonlyDeep<KeyType>, ReadonlyDeep<ValueType>>>;
70
71/**
72Same as `ReadonlyDeep`, but accepts only `ReadonlySet`s as inputs. Internal helper for `ReadonlyDeep`.
73*/
74type ReadonlySetDeep<ItemType> = {} & Readonly<ReadonlySet<ReadonlyDeep<ItemType>>>;
75
76/**
77Same as `ReadonlyDeep`, but accepts only `object`s as inputs. Internal helper for `ReadonlyDeep`.
78*/
79type ReadonlyObjectDeep<ObjectType extends object> = {
80 readonly [KeyType in keyof ObjectType]: ReadonlyDeep<ObjectType[KeyType]>
81};
82
\No newline at end of file