Merge pull request #12640 from Microsoft/mappedTypesSecondaryInferences

Classify mapped type inferences as secondary
This commit is contained in:
Anders Hejlsberg 2016-12-04 07:02:51 -08:00 committed by GitHub
commit 23992ba106
8 changed files with 178 additions and 4 deletions

View file

@ -8706,12 +8706,15 @@ namespace ts {
if (constraintType.flags & TypeFlags.Index) {
// We're inferring from some source type S to a homomorphic mapped type { [P in keyof T]: X },
// where T is a type variable. Use inferTypeForHomomorphicMappedType to infer a suitable source
// type and then infer from that type to T.
// type and then make a secondary inference from that type to T. We make a secondary inference
// such that direct inferences to T get priority over inferences to Partial<T>, for example.
const index = indexOf(typeVariables, (<IndexType>constraintType).type);
if (index >= 0 && !typeInferences[index].isFixed) {
const inferredType = inferTypeForHomomorphicMappedType(source, <MappedType>target);
if (inferredType) {
inferiority++;
inferFromTypes(inferredType, typeVariables[index]);
inferiority--;
}
}
return;

View file

@ -143,7 +143,14 @@ var g1 = applySpec({
});
// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } }
var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } });
var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } });
// Repro from #12633
const foo = <T>(object: T, partial: Partial<T>) => object;
let o = {a: 5, b: 7};
foo(o, {b: 9});
o = foo(o, {b: 9});
//// [isomorphicMappedTypeInference.js]
function box(x) {
@ -244,6 +251,11 @@ var g1 = applySpec({
});
// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } }
var g2 = applySpec({ foo: { bar: { baz: function (x) { return true; } } } });
// Repro from #12633
var foo = function (object, partial) { return object; };
var o = { a: 5, b: 7 };
foo(o, { b: 9 });
o = foo(o, { b: 9 });
//// [isomorphicMappedTypeInference.d.ts]
@ -311,3 +323,8 @@ declare var g2: (...args: any[]) => {
};
};
};
declare const foo: <T>(object: T, partial: Partial<T>) => T;
declare let o: {
a: number;
b: number;
};

View file

@ -459,3 +459,31 @@ var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } });
>baz : Symbol(baz, Decl(isomorphicMappedTypeInference.ts, 144, 34))
>x : Symbol(x, Decl(isomorphicMappedTypeInference.ts, 144, 41))
// Repro from #12633
const foo = <T>(object: T, partial: Partial<T>) => object;
>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 148, 5))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 148, 13))
>object : Symbol(object, Decl(isomorphicMappedTypeInference.ts, 148, 16))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 148, 13))
>partial : Symbol(partial, Decl(isomorphicMappedTypeInference.ts, 148, 26))
>Partial : Symbol(Partial, Decl(lib.d.ts, --, --))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 148, 13))
>object : Symbol(object, Decl(isomorphicMappedTypeInference.ts, 148, 16))
let o = {a: 5, b: 7};
>o : Symbol(o, Decl(isomorphicMappedTypeInference.ts, 149, 3))
>a : Symbol(a, Decl(isomorphicMappedTypeInference.ts, 149, 9))
>b : Symbol(b, Decl(isomorphicMappedTypeInference.ts, 149, 14))
foo(o, {b: 9});
>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 148, 5))
>o : Symbol(o, Decl(isomorphicMappedTypeInference.ts, 149, 3))
>b : Symbol(b, Decl(isomorphicMappedTypeInference.ts, 150, 8))
o = foo(o, {b: 9});
>o : Symbol(o, Decl(isomorphicMappedTypeInference.ts, 149, 3))
>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 148, 5))
>o : Symbol(o, Decl(isomorphicMappedTypeInference.ts, 149, 3))
>b : Symbol(b, Decl(isomorphicMappedTypeInference.ts, 151, 12))

View file

@ -546,3 +546,42 @@ var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } });
>x : any
>true : true
// Repro from #12633
const foo = <T>(object: T, partial: Partial<T>) => object;
>foo : <T>(object: T, partial: Partial<T>) => T
><T>(object: T, partial: Partial<T>) => object : <T>(object: T, partial: Partial<T>) => T
>T : T
>object : T
>T : T
>partial : Partial<T>
>Partial : Partial<T>
>T : T
>object : T
let o = {a: 5, b: 7};
>o : { a: number; b: number; }
>{a: 5, b: 7} : { a: number; b: number; }
>a : number
>5 : 5
>b : number
>7 : 7
foo(o, {b: 9});
>foo(o, {b: 9}) : { a: number; b: number; }
>foo : <T>(object: T, partial: Partial<T>) => T
>o : { a: number; b: number; }
>{b: 9} : { b: number; }
>b : number
>9 : 9
o = foo(o, {b: 9});
>o = foo(o, {b: 9}) : { a: number; b: number; }
>o : { a: number; b: number; }
>foo(o, {b: 9}) : { a: number; b: number; }
>foo : <T>(object: T, partial: Partial<T>) => T
>o : { a: number; b: number; }
>{b: 9} : { b: number; }
>b : number
>9 : 9

View file

@ -20,9 +20,15 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(60,9): error TS2403: Su
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(61,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]: T[P]; }'.
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(62,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]?: T[P] | undefined; }'.
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(67,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]: T[P][]; }'.
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(76,45): error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type 'Readonly<{ x: number; y: number; }>'.
Property 'y' is missing in type '{ x: number; }'.
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(78,59): error TS2345: Argument of type '{ x: number; y: number; z: number; }' is not assignable to parameter of type 'Readonly<{ x: number; y: number; }>'.
Object literal may only specify known properties, and 'z' does not exist in type 'Readonly<{ x: number; y: number; }>'.
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(84,58): error TS2345: Argument of type '{ x: number; y: number; z: number; }' is not assignable to parameter of type 'Partial<{ x: number; y: number; }>'.
Object literal may only specify known properties, and 'z' does not exist in type 'Partial<{ x: number; y: number; }>'.
==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (14 errors) ====
==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (17 errors) ====
interface Shape {
name: string;
@ -126,4 +132,30 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(67,9): error TS2403: Su
var x: { [P in keyof T]: T[P][] }; // Error
~
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]: T[P][]; }'.
}
// Check that inferences to mapped types are secondary
declare function objAndReadonly<T>(primary: T, secondary: Readonly<T>): T;
declare function objAndPartial<T>(primary: T, secondary: Partial<T>): T;
function f20() {
let x1 = objAndReadonly({ x: 0, y: 0 }, { x: 1 }); // Error
~~~~~~~~
!!! error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type 'Readonly<{ x: number; y: number; }>'.
!!! error TS2345: Property 'y' is missing in type '{ x: number; }'.
let x2 = objAndReadonly({ x: 0, y: 0 }, { x: 1, y: 1 });
let x3 = objAndReadonly({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error
~~~~
!!! error TS2345: Argument of type '{ x: number; y: number; z: number; }' is not assignable to parameter of type 'Readonly<{ x: number; y: number; }>'.
!!! error TS2345: Object literal may only specify known properties, and 'z' does not exist in type 'Readonly<{ x: number; y: number; }>'.
}
function f21() {
let x1 = objAndPartial({ x: 0, y: 0 }, { x: 1 });
let x2 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1 });
let x3 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error
~~~~
!!! error TS2345: Argument of type '{ x: number; y: number; z: number; }' is not assignable to parameter of type 'Partial<{ x: number; y: number; }>'.
!!! error TS2345: Object literal may only specify known properties, and 'z' does not exist in type 'Partial<{ x: number; y: number; }>'.
}

View file

@ -66,6 +66,23 @@ function f11<T>() {
function f12<T>() {
var x: { [P in keyof T]: T[P] };
var x: { [P in keyof T]: T[P][] }; // Error
}
// Check that inferences to mapped types are secondary
declare function objAndReadonly<T>(primary: T, secondary: Readonly<T>): T;
declare function objAndPartial<T>(primary: T, secondary: Partial<T>): T;
function f20() {
let x1 = objAndReadonly({ x: 0, y: 0 }, { x: 1 }); // Error
let x2 = objAndReadonly({ x: 0, y: 0 }, { x: 1, y: 1 });
let x3 = objAndReadonly({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error
}
function f21() {
let x1 = objAndPartial({ x: 0, y: 0 }, { x: 1 });
let x2 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1 });
let x3 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error
}
//// [mappedTypeErrors.js]
@ -97,6 +114,16 @@ function f12() {
var x;
var x; // Error
}
function f20() {
var x1 = objAndReadonly({ x: 0, y: 0 }, { x: 1 }); // Error
var x2 = objAndReadonly({ x: 0, y: 0 }, { x: 1, y: 1 });
var x3 = objAndReadonly({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error
}
function f21() {
var x1 = objAndPartial({ x: 0, y: 0 }, { x: 1 });
var x2 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1 });
var x3 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error
}
//// [mappedTypeErrors.d.ts]
@ -137,3 +164,7 @@ declare function f4<T extends keyof Named>(x: T): void;
declare function f10<T>(): void;
declare function f11<T>(): void;
declare function f12<T>(): void;
declare function objAndReadonly<T>(primary: T, secondary: Readonly<T>): T;
declare function objAndPartial<T>(primary: T, secondary: Partial<T>): T;
declare function f20(): void;
declare function f21(): void;

View file

@ -145,4 +145,11 @@ var g1 = applySpec({
});
// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } }
var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } });
var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } });
// Repro from #12633
const foo = <T>(object: T, partial: Partial<T>) => object;
let o = {a: 5, b: 7};
foo(o, {b: 9});
o = foo(o, {b: 9});

View file

@ -67,4 +67,21 @@ function f11<T>() {
function f12<T>() {
var x: { [P in keyof T]: T[P] };
var x: { [P in keyof T]: T[P][] }; // Error
}
// Check that inferences to mapped types are secondary
declare function objAndReadonly<T>(primary: T, secondary: Readonly<T>): T;
declare function objAndPartial<T>(primary: T, secondary: Partial<T>): T;
function f20() {
let x1 = objAndReadonly({ x: 0, y: 0 }, { x: 1 }); // Error
let x2 = objAndReadonly({ x: 0, y: 0 }, { x: 1, y: 1 });
let x3 = objAndReadonly({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error
}
function f21() {
let x1 = objAndPartial({ x: 0, y: 0 }, { x: 1 });
let x2 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1 });
let x3 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error
}