Skip to content

Commit 3ee234a

Browse files
authored
ReadonlyDeep: Skip constructor (#728)
1 parent 9baccc3 commit 3ee234a

2 files changed

Lines changed: 32 additions & 21 deletions

File tree

source/readonly-deep.d.ts

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,28 +38,30 @@ Note that types containing overloaded functions are not made deeply readonly due
3838
*/
3939
export type ReadonlyDeep<T> = T extends BuiltIns
4040
? T
41-
: T extends (...arguments_: any[]) => unknown
42-
? {} extends ReadonlyObjectDeep<T>
43-
? T
44-
: HasMultipleCallSignatures<T> extends true
41+
: T extends new (...args: any[]) => unknown
42+
? T // Skip class constructors
43+
: T extends (...arguments_: any[]) => unknown
44+
? {} extends ReadonlyObjectDeep<T>
4545
? T
46-
: ((...arguments_: Parameters<T>) => ReturnType<T>) & ReadonlyObjectDeep<T>
47-
: T extends Readonly<ReadonlyMap<infer KeyType, infer ValueType>>
48-
? ReadonlyMapDeep<KeyType, ValueType>
49-
: T extends Readonly<ReadonlySet<infer ItemType>>
50-
? ReadonlySetDeep<ItemType>
51-
: // Identify tuples to avoid converting them to arrays inadvertently; special case `readonly [...never[]]`, as it emerges undesirably from recursive invocations of ReadonlyDeep below.
52-
T extends readonly [] | readonly [...never[]]
53-
? readonly []
54-
: T extends readonly [infer U, ...infer V]
55-
? readonly [ReadonlyDeep<U>, ...ReadonlyDeep<V>]
56-
: T extends readonly [...infer U, infer V]
57-
? readonly [...ReadonlyDeep<U>, ReadonlyDeep<V>]
58-
: T extends ReadonlyArray<infer ItemType>
59-
? ReadonlyArray<ReadonlyDeep<ItemType>>
60-
: T extends object
61-
? ReadonlyObjectDeep<T>
62-
: unknown;
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;
6365

6466
/**
6567
Same as `ReadonlyDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `ReadonlyDeep`.

test-d/readonly-deep.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@ type ReadonlyJsonValue =
2828
| boolean
2929
| null;
3030

31+
class ClassA {
32+
foo = 1;
33+
}
34+
3135
const data = {
3236
object: {
3337
foo: 'bar',
3438
},
39+
constructor: ClassA,
3540
fn: (_: string) => true,
3641
fnWithOverload: ((_: number) => 'foo') as Overloaded,
3742
namespace: {} as unknown as Namespace,
@@ -66,6 +71,10 @@ readonlyData.fn('foo');
6671
readonlyData.fnWithOverload(1);
6772
readonlyData.fnWithOverload('', 1);
6873

74+
expectType<typeof ClassA>(readonlyData.constructor);
75+
const instance = new readonlyData.constructor();
76+
instance.foo = 2; // Constructor is not made readonly
77+
6978
expectError(readonlyData.string = 'bar');
7079
expectType<{readonly foo: string}>(readonlyData.object);
7180
expectType<string>(readonlyData.string);

0 commit comments

Comments
 (0)