Skip to content

Commit 1dbd5f3

Browse files
committed
Fixed const reverse mapped types themselves to be treated as const
1 parent 1a68590 commit 1dbd5f3

File tree

4 files changed

+266
-0
lines changed

4 files changed

+266
-0
lines changed

src/compiler/checker.ts

+6
Original file line numberDiff line numberDiff line change
@@ -13909,13 +13909,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1390913909
return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined;
1391013910
}
1391113911

13912+
function isConstMappedType(type: MappedType, depth: number): boolean {
13913+
const typeVariable = getHomomorphicTypeVariable(type);
13914+
return !!typeVariable && isConstTypeVariable(typeVariable, depth);
13915+
}
13916+
1391213917
function isConstTypeVariable(type: Type | undefined, depth = 0): boolean {
1391313918
return depth < 5 && !!(type && (
1391413919
type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) ||
1391513920
type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, t => isConstTypeVariable(t, depth)) ||
1391613921
type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType, depth + 1) ||
1391713922
type.flags & TypeFlags.Conditional && isConstTypeVariable(getConstraintOfConditionalType(type as ConditionalType), depth + 1) ||
1391813923
type.flags & TypeFlags.Substitution && isConstTypeVariable((type as SubstitutionType).baseType, depth) ||
13924+
getObjectFlags(type) & ObjectFlags.Mapped && isConstMappedType(type as MappedType, depth) ||
1391913925
isGenericTupleType(type) && findIndex(getElementTypes(type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t, depth)) >= 0
1392013926
));
1392113927
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
//// [tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiersReverseMappedTypes.ts] ////
2+
3+
=== typeParameterConstModifiersReverseMappedTypes.ts ===
4+
declare function test1<const T>(obj: {
5+
>test1 : Symbol(test1, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 0))
6+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 23))
7+
>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 32))
8+
9+
[K in keyof T]: T[K];
10+
>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 1, 3))
11+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 23))
12+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 23))
13+
>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 1, 3))
14+
15+
}): [T, typeof obj];
16+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 23))
17+
>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 32))
18+
19+
const result1 = test1({
20+
>result1 : Symbol(result1, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 4, 5))
21+
>test1 : Symbol(test1, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 0))
22+
23+
prop: "foo",
24+
>prop : Symbol(prop, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 4, 23))
25+
26+
nested: {
27+
>nested : Symbol(nested, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 5, 14))
28+
29+
nestedProp: "bar",
30+
>nestedProp : Symbol(nestedProp, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 6, 11))
31+
32+
},
33+
});
34+
35+
declare function test2<const T>(obj: {
36+
>test2 : Symbol(test2, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 9, 3))
37+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 23))
38+
>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 32))
39+
40+
readonly [K in keyof T]: T[K];
41+
>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 12, 12))
42+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 23))
43+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 23))
44+
>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 12, 12))
45+
46+
}): [T, typeof obj];
47+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 23))
48+
>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 32))
49+
50+
const result2 = test2({
51+
>result2 : Symbol(result2, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 15, 5))
52+
>test2 : Symbol(test2, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 9, 3))
53+
54+
prop: "foo",
55+
>prop : Symbol(prop, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 15, 23))
56+
57+
nested: {
58+
>nested : Symbol(nested, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 16, 14))
59+
60+
nestedProp: "bar",
61+
>nestedProp : Symbol(nestedProp, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 17, 11))
62+
63+
},
64+
});
65+
66+
declare function test3<const T>(obj: {
67+
>test3 : Symbol(test3, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 20, 3))
68+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 23))
69+
>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 32))
70+
71+
-readonly [K in keyof T]: T[K];
72+
>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 23, 13))
73+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 23))
74+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 23))
75+
>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 23, 13))
76+
77+
}): [T, typeof obj];
78+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 23))
79+
>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 32))
80+
81+
const result3 = test3({
82+
>result3 : Symbol(result3, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 26, 5))
83+
>test3 : Symbol(test3, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 20, 3))
84+
85+
prop: "foo",
86+
>prop : Symbol(prop, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 26, 23))
87+
88+
nested: {
89+
>nested : Symbol(nested, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 27, 14))
90+
91+
nestedProp: "bar",
92+
>nestedProp : Symbol(nestedProp, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 28, 11))
93+
94+
},
95+
});
96+
97+
declare function test4<const T extends readonly unknown[]>(arr: {
98+
>test4 : Symbol(test4, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 31, 3))
99+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 33, 23))
100+
>arr : Symbol(arr, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 33, 59))
101+
102+
[K in keyof T]: T[K];
103+
>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 34, 3))
104+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 33, 23))
105+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 33, 23))
106+
>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 34, 3))
107+
108+
}): T;
109+
>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 33, 23))
110+
111+
const result4 = test4(["1", 2]);
112+
>result4 : Symbol(result4, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 37, 5))
113+
>test4 : Symbol(test4, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 31, 3))
114+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//// [tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiersReverseMappedTypes.ts] ////
2+
3+
=== typeParameterConstModifiersReverseMappedTypes.ts ===
4+
declare function test1<const T>(obj: {
5+
>test1 : <const T>(obj: { [K in keyof T]: T[K]; }) => [T, typeof obj]
6+
>obj : { [K in keyof T]: T[K]; }
7+
8+
[K in keyof T]: T[K];
9+
}): [T, typeof obj];
10+
>obj : { [K in keyof T]: T[K]; }
11+
12+
const result1 = test1({
13+
>result1 : [{ readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }, { readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }]
14+
>test1({ prop: "foo", nested: { nestedProp: "bar", },}) : [{ readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }, { readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }]
15+
>test1 : <const T>(obj: { [K in keyof T]: T[K]; }) => [T, { [K in keyof T]: T[K]; }]
16+
>{ prop: "foo", nested: { nestedProp: "bar", },} : { prop: "foo"; nested: { nestedProp: "bar"; }; }
17+
18+
prop: "foo",
19+
>prop : "foo"
20+
>"foo" : "foo"
21+
22+
nested: {
23+
>nested : { nestedProp: "bar"; }
24+
>{ nestedProp: "bar", } : { nestedProp: "bar"; }
25+
26+
nestedProp: "bar",
27+
>nestedProp : "bar"
28+
>"bar" : "bar"
29+
30+
},
31+
});
32+
33+
declare function test2<const T>(obj: {
34+
>test2 : <const T>(obj: { readonly [K in keyof T]: T[K]; }) => [T, typeof obj]
35+
>obj : { readonly [K in keyof T]: T[K]; }
36+
37+
readonly [K in keyof T]: T[K];
38+
}): [T, typeof obj];
39+
>obj : { readonly [K in keyof T]: T[K]; }
40+
41+
const result2 = test2({
42+
>result2 : [{ prop: "foo"; nested: { readonly nestedProp: "bar"; }; }, { readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }]
43+
>test2({ prop: "foo", nested: { nestedProp: "bar", },}) : [{ prop: "foo"; nested: { readonly nestedProp: "bar"; }; }, { readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }]
44+
>test2 : <const T>(obj: { readonly [K in keyof T]: T[K]; }) => [T, { readonly [K in keyof T]: T[K]; }]
45+
>{ prop: "foo", nested: { nestedProp: "bar", },} : { prop: "foo"; nested: { nestedProp: "bar"; }; }
46+
47+
prop: "foo",
48+
>prop : "foo"
49+
>"foo" : "foo"
50+
51+
nested: {
52+
>nested : { nestedProp: "bar"; }
53+
>{ nestedProp: "bar", } : { nestedProp: "bar"; }
54+
55+
nestedProp: "bar",
56+
>nestedProp : "bar"
57+
>"bar" : "bar"
58+
59+
},
60+
});
61+
62+
declare function test3<const T>(obj: {
63+
>test3 : <const T>(obj: { -readonly [K in keyof T]: T[K]; }) => [T, typeof obj]
64+
>obj : { -readonly [K in keyof T]: T[K]; }
65+
66+
-readonly [K in keyof T]: T[K];
67+
}): [T, typeof obj];
68+
>obj : { -readonly [K in keyof T]: T[K]; }
69+
70+
const result3 = test3({
71+
>result3 : [{ readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }, { prop: "foo"; nested: { readonly nestedProp: "bar"; }; }]
72+
>test3({ prop: "foo", nested: { nestedProp: "bar", },}) : [{ readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }, { prop: "foo"; nested: { readonly nestedProp: "bar"; }; }]
73+
>test3 : <const T>(obj: { -readonly [K in keyof T]: T[K]; }) => [T, { -readonly [K in keyof T]: T[K]; }]
74+
>{ prop: "foo", nested: { nestedProp: "bar", },} : { prop: "foo"; nested: { nestedProp: "bar"; }; }
75+
76+
prop: "foo",
77+
>prop : "foo"
78+
>"foo" : "foo"
79+
80+
nested: {
81+
>nested : { nestedProp: "bar"; }
82+
>{ nestedProp: "bar", } : { nestedProp: "bar"; }
83+
84+
nestedProp: "bar",
85+
>nestedProp : "bar"
86+
>"bar" : "bar"
87+
88+
},
89+
});
90+
91+
declare function test4<const T extends readonly unknown[]>(arr: {
92+
>test4 : <const T extends readonly unknown[]>(arr: { [K in keyof T]: T[K]; }) => T
93+
>arr : { [K in keyof T]: T[K]; }
94+
95+
[K in keyof T]: T[K];
96+
}): T;
97+
98+
const result4 = test4(["1", 2]);
99+
>result4 : readonly ["1", 2]
100+
>test4(["1", 2]) : readonly ["1", 2]
101+
>test4 : <const T extends readonly unknown[]>(arr: { [K in keyof T]: T[K]; }) => T
102+
>["1", 2] : ["1", 2]
103+
>"1" : "1"
104+
>2 : 2
105+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
declare function test1<const T>(obj: {
5+
[K in keyof T]: T[K];
6+
}): [T, typeof obj];
7+
8+
const result1 = test1({
9+
prop: "foo",
10+
nested: {
11+
nestedProp: "bar",
12+
},
13+
});
14+
15+
declare function test2<const T>(obj: {
16+
readonly [K in keyof T]: T[K];
17+
}): [T, typeof obj];
18+
19+
const result2 = test2({
20+
prop: "foo",
21+
nested: {
22+
nestedProp: "bar",
23+
},
24+
});
25+
26+
declare function test3<const T>(obj: {
27+
-readonly [K in keyof T]: T[K];
28+
}): [T, typeof obj];
29+
30+
const result3 = test3({
31+
prop: "foo",
32+
nested: {
33+
nestedProp: "bar",
34+
},
35+
});
36+
37+
declare function test4<const T extends readonly unknown[]>(arr: {
38+
[K in keyof T]: T[K];
39+
}): T;
40+
41+
const result4 = test4(["1", 2]);

0 commit comments

Comments
 (0)