Merge pull request #30801 from Microsoft/tweakUnionTypeInference

Tweak union type inference
This commit is contained in:
Anders Hejlsberg 2019-04-06 21:13:30 -07:00 committed by GitHub
commit 89386ddda7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 8 deletions

View File

@ -14770,17 +14770,25 @@ namespace ts {
inferFromTypes(source, (<ConditionalType>target).falseType);
}
else if (target.flags & TypeFlags.UnionOrIntersection) {
// We infer from types that are not naked type variables first so that inferences we
// make from nested naked type variables and given slightly higher priority by virtue
// of being first in the candidates array.
for (const t of (<UnionOrIntersectionType>target).types) {
const savePriority = priority;
// Inferences directly to naked type variables are given lower priority as they are
// less specific. For example, when inferring from Promise<string> to T | Promise<T>,
// we want to infer string for T, not Promise<string> | string.
if (getInferenceInfoForType(t)) {
priority |= InferencePriority.NakedTypeVariable;
if (!getInferenceInfoForType(t)) {
inferFromTypes(source, t);
}
inferFromTypes(source, t);
priority = savePriority;
}
// Inferences directly to naked type variables are given lower priority as they are
// less specific. For example, when inferring from Promise<string> to T | Promise<T>,
// we want to infer string for T, not Promise<string> | string.
const savePriority = priority;
priority |= InferencePriority.NakedTypeVariable;
for (const t of (<UnionOrIntersectionType>target).types) {
if (getInferenceInfoForType(t)) {
inferFromTypes(source, t);
}
}
priority = savePriority;
}
else if (source.flags & TypeFlags.Union) {
// Source is a union or intersection type, infer from each constituent type

View File

@ -0,0 +1,12 @@
//// [unionAndIntersectionInference3.ts]
// Repro from #30720
type Maybe<T> = T | undefined;
declare function concatMaybe<T>(...args: (Maybe<T> | Maybe<T>[])[]): T[];
concatMaybe([1, 2, 3], 4);
//// [unionAndIntersectionInference3.js]
"use strict";
// Repro from #30720
concatMaybe([1, 2, 3], 4);

View File

@ -0,0 +1,21 @@
=== tests/cases/conformance/types/typeRelationships/typeInference/unionAndIntersectionInference3.ts ===
// Repro from #30720
type Maybe<T> = T | undefined;
>Maybe : Symbol(Maybe, Decl(unionAndIntersectionInference3.ts, 0, 0))
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 2, 11))
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 2, 11))
declare function concatMaybe<T>(...args: (Maybe<T> | Maybe<T>[])[]): T[];
>concatMaybe : Symbol(concatMaybe, Decl(unionAndIntersectionInference3.ts, 2, 30))
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 3, 29))
>args : Symbol(args, Decl(unionAndIntersectionInference3.ts, 3, 32))
>Maybe : Symbol(Maybe, Decl(unionAndIntersectionInference3.ts, 0, 0))
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 3, 29))
>Maybe : Symbol(Maybe, Decl(unionAndIntersectionInference3.ts, 0, 0))
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 3, 29))
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 3, 29))
concatMaybe([1, 2, 3], 4);
>concatMaybe : Symbol(concatMaybe, Decl(unionAndIntersectionInference3.ts, 2, 30))

View File

@ -0,0 +1,19 @@
=== tests/cases/conformance/types/typeRelationships/typeInference/unionAndIntersectionInference3.ts ===
// Repro from #30720
type Maybe<T> = T | undefined;
>Maybe : Maybe<T>
declare function concatMaybe<T>(...args: (Maybe<T> | Maybe<T>[])[]): T[];
>concatMaybe : <T>(...args: (T | Maybe<T>[] | undefined)[]) => T[]
>args : (T | Maybe<T>[] | undefined)[]
concatMaybe([1, 2, 3], 4);
>concatMaybe([1, 2, 3], 4) : number[]
>concatMaybe : <T>(...args: (T | Maybe<T>[] | undefined)[]) => T[]
>[1, 2, 3] : number[]
>1 : 1
>2 : 2
>3 : 3
>4 : 4

View File

@ -0,0 +1,7 @@
// @strict: true
// Repro from #30720
type Maybe<T> = T | undefined;
declare function concatMaybe<T>(...args: (Maybe<T> | Maybe<T>[])[]): T[];
concatMaybe([1, 2, 3], 4);