Skip to content

Commit f3ad09a

Browse files
authored
Merge pull request #13061 from Microsoft/fixMappedTypeConstraint
Fix mapped type constraint checking
2 parents 8ae0376 + e569edd commit f3ad09a

File tree

4 files changed

+72
-6
lines changed

4 files changed

+72
-6
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4612,8 +4612,8 @@ namespace ts {
46124612
// the modifiers type is T. Otherwise, the modifiers type is {}.
46134613
const declaredType = <MappedType>getTypeFromMappedTypeNode(type.declaration);
46144614
const constraint = getConstraintTypeFromMappedType(declaredType);
4615-
const extendedConstraint = constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(<TypeParameter>constraint) : constraint;
4616-
type.modifiersType = extendedConstraint.flags & TypeFlags.Index ? instantiateType((<IndexType>extendedConstraint).type, type.mapper || identityMapper) : emptyObjectType;
4615+
const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(<TypeParameter>constraint) : constraint;
4616+
type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? instantiateType((<IndexType>extendedConstraint).type, type.mapper || identityMapper) : emptyObjectType;
46174617
}
46184618
}
46194619
return type.modifiersType;

tests/baselines/reference/mappedTypeErrors.errors.txt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(130,5): error TS2322: T
4545
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(131,5): error TS2322: Type '{ a: string; }' is not assignable to type '{ [x: string]: any; a?: number | undefined; }'.
4646
Types of property 'a' are incompatible.
4747
Type 'string' is not assignable to type 'number | undefined'.
48+
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(137,16): error TS2322: Type '{}' is not assignable to type 'string'.
49+
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(137,21): error TS2536: Type 'P' cannot be used to index type 'T'.
4850

4951

50-
==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (24 errors) ====
52+
==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (26 errors) ====
5153

5254
interface Shape {
5355
name: string;
@@ -249,4 +251,22 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(131,5): error TS2322: T
249251
~~
250252
!!! error TS2322: Type '{ a: string; }' is not assignable to type '{ [x: string]: any; a?: number | undefined; }'.
251253
!!! error TS2322: Types of property 'a' are incompatible.
252-
!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'.
254+
!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'.
255+
256+
// Repro from #13044
257+
258+
type Foo2<T, F extends keyof T> = {
259+
pf: {[P in F]?: T[P]},
260+
pt: {[P in T]?: T[P]}, // note: should be in keyof T
261+
~
262+
!!! error TS2322: Type '{}' is not assignable to type 'string'.
263+
~~~~
264+
!!! error TS2536: Type 'P' cannot be used to index type 'T'.
265+
};
266+
type O = {x: number, y: boolean};
267+
let o: O = {x: 5, y: false};
268+
let f: Foo2<O, 'x'> = {
269+
pf: {x: 7},
270+
pt: {x: 7, y: false},
271+
};
272+

tests/baselines/reference/mappedTypeErrors.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,21 @@ type T2 = { a?: number, [key: string]: any };
129129

130130
let x1: T2 = { a: 'no' }; // Error
131131
let x2: Partial<T2> = { a: 'no' }; // Error
132-
let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error
132+
let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error
133+
134+
// Repro from #13044
135+
136+
type Foo2<T, F extends keyof T> = {
137+
pf: {[P in F]?: T[P]},
138+
pt: {[P in T]?: T[P]}, // note: should be in keyof T
139+
};
140+
type O = {x: number, y: boolean};
141+
let o: O = {x: 5, y: false};
142+
let f: Foo2<O, 'x'> = {
143+
pf: {x: 7},
144+
pt: {x: 7, y: false},
145+
};
146+
133147

134148
//// [mappedTypeErrors.js]
135149
function f1(x) {
@@ -204,6 +218,11 @@ c.setState({ c: true }); // Error
204218
var x1 = { a: 'no' }; // Error
205219
var x2 = { a: 'no' }; // Error
206220
var x3 = { a: 'no' }; // Error
221+
var o = { x: 5, y: false };
222+
var f = {
223+
pf: { x: 7 },
224+
pt: { x: 7, y: false }
225+
};
207226

208227

209228
//// [mappedTypeErrors.d.ts]
@@ -268,3 +287,17 @@ declare let x2: Partial<T2>;
268287
declare let x3: {
269288
[P in keyof T2]: T2[P];
270289
};
290+
declare type Foo2<T, F extends keyof T> = {
291+
pf: {
292+
[P in F]?: T[P];
293+
};
294+
pt: {
295+
[P in T]?: T[P];
296+
};
297+
};
298+
declare type O = {
299+
x: number;
300+
y: boolean;
301+
};
302+
declare let o: O;
303+
declare let f: Foo2<O, 'x'>;

tests/cases/conformance/types/mapped/mappedTypeErrors.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,17 @@ type T2 = { a?: number, [key: string]: any };
130130

131131
let x1: T2 = { a: 'no' }; // Error
132132
let x2: Partial<T2> = { a: 'no' }; // Error
133-
let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error
133+
let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error
134+
135+
// Repro from #13044
136+
137+
type Foo2<T, F extends keyof T> = {
138+
pf: {[P in F]?: T[P]},
139+
pt: {[P in T]?: T[P]}, // note: should be in keyof T
140+
};
141+
type O = {x: number, y: boolean};
142+
let o: O = {x: 5, y: false};
143+
let f: Foo2<O, 'x'> = {
144+
pf: {x: 7},
145+
pt: {x: 7, y: false},
146+
};

0 commit comments

Comments
 (0)