Skip to content

Commit

Permalink
Merge pull request #30801 from Microsoft/tweakUnionTypeInference
Browse files Browse the repository at this point in the history
Tweak union type inference
  • Loading branch information
ahejlsberg committed Apr 7, 2019
2 parents 60346b5 + 40827eb commit 89386dd
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 7 deletions.
22 changes: 15 additions & 7 deletions src/compiler/checker.ts
Expand Up @@ -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) {
if (!getInferenceInfoForType(t)) {
inferFromTypes(source, t);
}
}
// 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) {
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;
inferFromTypes(source, t);
}
inferFromTypes(source, t);
priority = savePriority;
}
priority = savePriority;
}
else if (source.flags & TypeFlags.Union) {
// Source is a union or intersection type, infer from each constituent type
Expand Down
12 changes: 12 additions & 0 deletions tests/baselines/reference/unionAndIntersectionInference3.js
@@ -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);
21 changes: 21 additions & 0 deletions tests/baselines/reference/unionAndIntersectionInference3.symbols
@@ -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))

19 changes: 19 additions & 0 deletions tests/baselines/reference/unionAndIntersectionInference3.types
@@ -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

@@ -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);

0 comments on commit 89386dd

Please sign in to comment.