Merge pull request #19701 from Microsoft/fixIntersectionTypeInference

Fix intersection type inference
This commit is contained in:
Anders Hejlsberg
2017-11-03 06:52:05 -07:00
committed by GitHub
6 changed files with 170 additions and 7 deletions
+1 -1
View File
@@ -10807,7 +10807,7 @@ namespace ts {
}
function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean) {
const properties = getPropertiesOfObjectType(target);
const properties = target.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(<IntersectionType>target) : getPropertiesOfObjectType(target);
for (const targetProp of properties) {
if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional)) {
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
@@ -0,0 +1,25 @@
//// [intersectionTypeInference3.ts]
// Repro from #19682
type Nominal<Kind extends string, Type> = Type & {
[Symbol.species]: Kind;
};
type A = Nominal<'A', string>;
declare const a: Set<A>;
declare const b: Set<A>;
const c1 = Array.from(a).concat(Array.from(b));
// Simpler repro
declare function from<T>(): T[];
const c2: ReadonlyArray<A> = from();
//// [intersectionTypeInference3.js]
"use strict";
// Repro from #19682
const c1 = Array.from(a).concat(Array.from(b));
const c2 = from();
@@ -0,0 +1,57 @@
=== tests/cases/conformance/types/intersection/intersectionTypeInference3.ts ===
// Repro from #19682
type Nominal<Kind extends string, Type> = Type & {
>Nominal : Symbol(Nominal, Decl(intersectionTypeInference3.ts, 0, 0))
>Kind : Symbol(Kind, Decl(intersectionTypeInference3.ts, 2, 13))
>Type : Symbol(Type, Decl(intersectionTypeInference3.ts, 2, 33))
>Type : Symbol(Type, Decl(intersectionTypeInference3.ts, 2, 33))
[Symbol.species]: Kind;
>Symbol.species : Symbol(SymbolConstructor.species, Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --))
>species : Symbol(SymbolConstructor.species, Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>Kind : Symbol(Kind, Decl(intersectionTypeInference3.ts, 2, 13))
};
type A = Nominal<'A', string>;
>A : Symbol(A, Decl(intersectionTypeInference3.ts, 4, 2))
>Nominal : Symbol(Nominal, Decl(intersectionTypeInference3.ts, 0, 0))
declare const a: Set<A>;
>a : Symbol(a, Decl(intersectionTypeInference3.ts, 8, 13))
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
>A : Symbol(A, Decl(intersectionTypeInference3.ts, 4, 2))
declare const b: Set<A>;
>b : Symbol(b, Decl(intersectionTypeInference3.ts, 9, 13))
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
>A : Symbol(A, Decl(intersectionTypeInference3.ts, 4, 2))
const c1 = Array.from(a).concat(Array.from(b));
>c1 : Symbol(c1, Decl(intersectionTypeInference3.ts, 11, 5))
>Array.from(a).concat : Symbol(Array.concat, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>a : Symbol(a, Decl(intersectionTypeInference3.ts, 8, 13))
>concat : Symbol(Array.concat, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>b : Symbol(b, Decl(intersectionTypeInference3.ts, 9, 13))
// Simpler repro
declare function from<T>(): T[];
>from : Symbol(from, Decl(intersectionTypeInference3.ts, 11, 47))
>T : Symbol(T, Decl(intersectionTypeInference3.ts, 15, 22))
>T : Symbol(T, Decl(intersectionTypeInference3.ts, 15, 22))
const c2: ReadonlyArray<A> = from();
>c2 : Symbol(c2, Decl(intersectionTypeInference3.ts, 16, 5))
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>A : Symbol(A, Decl(intersectionTypeInference3.ts, 4, 2))
>from : Symbol(from, Decl(intersectionTypeInference3.ts, 11, 47))
@@ -0,0 +1,61 @@
=== tests/cases/conformance/types/intersection/intersectionTypeInference3.ts ===
// Repro from #19682
type Nominal<Kind extends string, Type> = Type & {
>Nominal : Nominal<Kind, Type>
>Kind : Kind
>Type : Type
>Type : Type
[Symbol.species]: Kind;
>Symbol.species : symbol
>Symbol : SymbolConstructor
>species : symbol
>Kind : Kind
};
type A = Nominal<'A', string>;
>A : Nominal<"A", string>
>Nominal : Nominal<Kind, Type>
declare const a: Set<A>;
>a : Set<Nominal<"A", string>>
>Set : Set<T>
>A : Nominal<"A", string>
declare const b: Set<A>;
>b : Set<Nominal<"A", string>>
>Set : Set<T>
>A : Nominal<"A", string>
const c1 = Array.from(a).concat(Array.from(b));
>c1 : Nominal<"A", string>[]
>Array.from(a).concat(Array.from(b)) : Nominal<"A", string>[]
>Array.from(a).concat : { (...items: ReadonlyArray<Nominal<"A", string>>[]): Nominal<"A", string>[]; (...items: (Nominal<"A", string> | ReadonlyArray<Nominal<"A", string>>)[]): Nominal<"A", string>[]; }
>Array.from(a) : Nominal<"A", string>[]
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>a : Set<Nominal<"A", string>>
>concat : { (...items: ReadonlyArray<Nominal<"A", string>>[]): Nominal<"A", string>[]; (...items: (Nominal<"A", string> | ReadonlyArray<Nominal<"A", string>>)[]): Nominal<"A", string>[]; }
>Array.from(b) : Nominal<"A", string>[]
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>b : Set<Nominal<"A", string>>
// Simpler repro
declare function from<T>(): T[];
>from : <T>() => T[]
>T : T
>T : T
const c2: ReadonlyArray<A> = from();
>c2 : ReadonlyArray<Nominal<"A", string>>
>ReadonlyArray : ReadonlyArray<T>
>A : Nominal<"A", string>
>from() : Nominal<"A", string>[]
>from : <T>() => T[]
@@ -1,9 +1,9 @@
tests/cases/conformance/jsx/file.tsx(9,33): error TS2322: Type '{ a: number; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: number; }'.
Type '{ a: number; }' is not assignable to type '{ b: {}; a: number; }'.
Property 'b' is missing in type '{ a: number; }'.
tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'.
Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'.
Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'.
tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'.
Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'.
Type '{ b: number; }' is not assignable to type '{ b: {}; a: {}; }'.
Property 'a' is missing in type '{ b: number; }'.
Type 'T' is not assignable to type 'IntrinsicAttributes'.
Type '{ b: number; }' has no properties in common with type 'IntrinsicAttributes'.
@@ -25,9 +25,9 @@ tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type 'T' is not assig
!!! error TS2322: Property 'b' is missing in type '{ a: number; }'.
let a2 = <OverloadComponent {...arg1} ignore-prop /> // missing a
~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'.
!!! error TS2322: Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'.
!!! error TS2322: Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'.
!!! error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'.
!!! error TS2322: Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'.
!!! error TS2322: Type '{ b: number; }' is not assignable to type '{ b: {}; a: {}; }'.
!!! error TS2322: Property 'a' is missing in type '{ b: number; }'.
!!! error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes'.
!!! error TS2322: Type '{ b: number; }' has no properties in common with type 'IntrinsicAttributes'.
@@ -0,0 +1,20 @@
// @strict: true
// @target: es2015
// Repro from #19682
type Nominal<Kind extends string, Type> = Type & {
[Symbol.species]: Kind;
};
type A = Nominal<'A', string>;
declare const a: Set<A>;
declare const b: Set<A>;
const c1 = Array.from(a).concat(Array.from(b));
// Simpler repro
declare function from<T>(): T[];
const c2: ReadonlyArray<A> = from();