Skip to content

Fix mapped type constraint checking #13061

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4612,8 +4612,8 @@ namespace ts {
// the modifiers type is T. Otherwise, the modifiers type is {}.
const declaredType = <MappedType>getTypeFromMappedTypeNode(type.declaration);
const constraint = getConstraintTypeFromMappedType(declaredType);
const extendedConstraint = constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(<TypeParameter>constraint) : constraint;
type.modifiersType = extendedConstraint.flags & TypeFlags.Index ? instantiateType((<IndexType>extendedConstraint).type, type.mapper || identityMapper) : emptyObjectType;
const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(<TypeParameter>constraint) : constraint;
type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? instantiateType((<IndexType>extendedConstraint).type, type.mapper || identityMapper) : emptyObjectType;
}
}
return type.modifiersType;
Expand Down
24 changes: 22 additions & 2 deletions tests/baselines/reference/mappedTypeErrors.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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'.
!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'.

// Repro from #13044

type Foo2<T, F extends keyof T> = {
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<O, 'x'> = {
pf: {x: 7},
pt: {x: 7, y: false},
};

35 changes: 34 additions & 1 deletion tests/baselines/reference/mappedTypeErrors.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,21 @@ type T2 = { a?: number, [key: string]: any };

let x1: T2 = { a: 'no' }; // Error
let x2: Partial<T2> = { 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<T, F extends keyof T> = {
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<O, 'x'> = {
pf: {x: 7},
pt: {x: 7, y: false},
};


//// [mappedTypeErrors.js]
function f1(x) {
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -268,3 +287,17 @@ declare let x2: Partial<T2>;
declare let x3: {
[P in keyof T2]: T2[P];
};
declare type Foo2<T, F extends keyof T> = {
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<O, 'x'>;
15 changes: 14 additions & 1 deletion tests/cases/conformance/types/mapped/mappedTypeErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,17 @@ type T2 = { a?: number, [key: string]: any };

let x1: T2 = { a: 'no' }; // Error
let x2: Partial<T2> = { 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<T, F extends keyof T> = {
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<O, 'x'> = {
pf: {x: 7},
pt: {x: 7, y: false},
};