diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1c22fc36207df..36b952dd046fa 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4612,8 +4612,8 @@ namespace ts { // the modifiers type is T. Otherwise, the modifiers type is {}. const declaredType = getTypeFromMappedTypeNode(type.declaration); const constraint = getConstraintTypeFromMappedType(declaredType); - const extendedConstraint = constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(constraint) : constraint; - type.modifiersType = extendedConstraint.flags & TypeFlags.Index ? instantiateType((extendedConstraint).type, type.mapper || identityMapper) : emptyObjectType; + const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(constraint) : constraint; + type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? instantiateType((extendedConstraint).type, type.mapper || identityMapper) : emptyObjectType; } } return type.modifiersType; diff --git a/tests/baselines/reference/mappedTypeErrors.errors.txt b/tests/baselines/reference/mappedTypeErrors.errors.txt index f98a11dbaf9be..94644a96af9bd 100644 --- a/tests/baselines/reference/mappedTypeErrors.errors.txt +++ b/tests/baselines/reference/mappedTypeErrors.errors.txt @@ -45,9 +45,11 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(130,5): error TS2322: T 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; }'. Types of property 'a' are incompatible. Type 'string' is not assignable to type 'number | undefined'. +tests/cases/conformance/types/mapped/mappedTypeErrors.ts(137,16): error TS2322: Type '{}' is not assignable to type 'string'. +tests/cases/conformance/types/mapped/mappedTypeErrors.ts(137,21): error TS2536: Type 'P' cannot be used to index type 'T'. -==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (24 errors) ==== +==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (26 errors) ==== interface Shape { name: string; @@ -249,4 +251,22 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(131,5): error TS2322: T ~~ !!! error TS2322: Type '{ a: string; }' is not assignable to type '{ [x: string]: any; a?: number | undefined; }'. !!! error TS2322: Types of property 'a' are incompatible. -!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'. \ No newline at end of file +!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'. + + // Repro from #13044 + + type Foo2 = { + pf: {[P in F]?: T[P]}, + pt: {[P in T]?: T[P]}, // note: should be in keyof T + ~ +!!! error TS2322: Type '{}' is not assignable to type 'string'. + ~~~~ +!!! error TS2536: Type 'P' cannot be used to index type 'T'. + }; + type O = {x: number, y: boolean}; + let o: O = {x: 5, y: false}; + let f: Foo2 = { + pf: {x: 7}, + pt: {x: 7, y: false}, + }; + \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeErrors.js b/tests/baselines/reference/mappedTypeErrors.js index 83dc235c7059e..f194b6193fc37 100644 --- a/tests/baselines/reference/mappedTypeErrors.js +++ b/tests/baselines/reference/mappedTypeErrors.js @@ -129,7 +129,21 @@ type T2 = { a?: number, [key: string]: any }; let x1: T2 = { a: 'no' }; // Error let x2: Partial = { a: 'no' }; // Error -let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error +let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error + +// Repro from #13044 + +type Foo2 = { + pf: {[P in F]?: T[P]}, + pt: {[P in T]?: T[P]}, // note: should be in keyof T +}; +type O = {x: number, y: boolean}; +let o: O = {x: 5, y: false}; +let f: Foo2 = { + pf: {x: 7}, + pt: {x: 7, y: false}, +}; + //// [mappedTypeErrors.js] function f1(x) { @@ -204,6 +218,11 @@ c.setState({ c: true }); // Error var x1 = { a: 'no' }; // Error var x2 = { a: 'no' }; // Error var x3 = { a: 'no' }; // Error +var o = { x: 5, y: false }; +var f = { + pf: { x: 7 }, + pt: { x: 7, y: false } +}; //// [mappedTypeErrors.d.ts] @@ -268,3 +287,17 @@ declare let x2: Partial; declare let x3: { [P in keyof T2]: T2[P]; }; +declare type Foo2 = { + pf: { + [P in F]?: T[P]; + }; + pt: { + [P in T]?: T[P]; + }; +}; +declare type O = { + x: number; + y: boolean; +}; +declare let o: O; +declare let f: Foo2; diff --git a/tests/cases/conformance/types/mapped/mappedTypeErrors.ts b/tests/cases/conformance/types/mapped/mappedTypeErrors.ts index 458dbe9caa412..cec1fbf839554 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeErrors.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeErrors.ts @@ -130,4 +130,17 @@ type T2 = { a?: number, [key: string]: any }; let x1: T2 = { a: 'no' }; // Error let x2: Partial = { a: 'no' }; // Error -let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error \ No newline at end of file +let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error + +// Repro from #13044 + +type Foo2 = { + pf: {[P in F]?: T[P]}, + pt: {[P in T]?: T[P]}, // note: should be in keyof T +}; +type O = {x: number, y: boolean}; +let o: O = {x: 5, y: false}; +let f: Foo2 = { + pf: {x: 7}, + pt: {x: 7, y: false}, +};