Skip to content

Commit 9ec71c3

Browse files
authored
Merge pull request #32460 from microsoft/fix32434
Improve type inference for types like 'T | Promise<T>'
2 parents d982014 + 5646856 commit 9ec71c3

File tree

7 files changed

+630
-325
lines changed

7 files changed

+630
-325
lines changed

src/compiler/checker.ts

Lines changed: 133 additions & 60 deletions
Large diffs are not rendered by default.

tests/baselines/reference/unionAndIntersectionInference2.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ var e1: number | string | boolean;
2020
>e1 : string | number | boolean
2121

2222
f1(a1); // string
23-
>f1(a1) : string
23+
>f1(a1) : unknown
2424
>f1 : <T>(x: string | T) => T
2525
>a1 : string
2626

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,61 @@
1-
tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(9,15): error TS2345: Argument of type '2' is not assignable to parameter of type 'string | 1'.
1+
tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(13,24): error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
2+
tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(31,15): error TS2345: Argument of type '42' is not assignable to parameter of type 'never'.
23

34

4-
==== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts (1 errors) ====
5-
// Verify that inferences made *to* a type parameter in a union type are secondary
6-
// to inferences made directly to that type parameter
5+
==== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts (2 errors) ====
6+
declare const b: boolean;
7+
declare const s: string;
8+
declare const sn: string | number;
79

8-
function f<T>(x: T, y: string|T): T {
9-
return x;
10+
declare function f1<T>(x: T, y: string | T): T;
11+
12+
const a1 = f1(1, 2); // 1 | 2
13+
const a2 = f1(1, "hello"); // 1
14+
const a3 = f1(1, sn); // number
15+
const a4 = f1(undefined, "abc"); // undefined
16+
const a5 = f1("foo", "bar"); // "foo"
17+
const a6 = f1(true, false); // boolean
18+
const a7 = f1("hello", 1); // Error
19+
~
20+
!!! error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
21+
22+
declare function f2<T>(value: [string, T]): T;
23+
24+
var b1 = f2(["string", true]); // boolean
25+
26+
declare function f3<T>(x: string | false | T): T;
27+
28+
const c1 = f3(5); // 5
29+
const c2 = f3(sn); // number
30+
const c3 = f3(true); // true
31+
const c4 = f3(b); // true
32+
const c5 = f3("abc"); // never
33+
34+
declare function f4<T>(x: string & T): T;
35+
36+
const d1 = f4("abc");
37+
const d2 = f4(s);
38+
const d3 = f4(42); // Error
39+
~~
40+
!!! error TS2345: Argument of type '42' is not assignable to parameter of type 'never'.
41+
42+
export interface Foo<T> {
43+
then<U>(f: (x: T) => U | Foo<U>, g: U): Foo<U>;
44+
}
45+
export interface Bar<T> {
46+
then<S>(f: (x: T) => S | Bar<S>, g: S): Bar<S>;
1047
}
1148

12-
var a1: number;
13-
var a1 = f(1, 2);
14-
~
15-
!!! error TS2345: Argument of type '2' is not assignable to parameter of type 'string | 1'.
16-
var a2: number;
17-
var a2 = f(1, "hello");
18-
var a3: number;
19-
var a3 = f(1, a1 || "hello");
20-
var a4: any;
21-
var a4 = f(undefined, "abc");
22-
23-
function g<T>(value: [string, T]): T {
24-
return value[1];
49+
function qux(p1: Foo<void>, p2: Bar<void>) {
50+
p1 = p2;
2551
}
2652

27-
var b1: boolean;
28-
var b1 = g(["string", true]);
53+
// Repros from #32434
2954

30-
function h<T>(x: string|boolean|T): T {
31-
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
32-
}
55+
declare function foo<T>(x: T | Promise<T>): void;
56+
declare let x: false | Promise<true>;
57+
foo(x);
3358

34-
var c1: number;
35-
var c1 = h(5);
36-
var c2: string;
37-
var c2 = h("abc");
59+
declare function bar<T>(x: T, y: string | T): T;
60+
const y = bar(1, 2);
3861

Lines changed: 66 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,78 @@
11
//// [unionTypeInference.ts]
2-
// Verify that inferences made *to* a type parameter in a union type are secondary
3-
// to inferences made directly to that type parameter
2+
declare const b: boolean;
3+
declare const s: string;
4+
declare const sn: string | number;
45

5-
function f<T>(x: T, y: string|T): T {
6-
return x;
6+
declare function f1<T>(x: T, y: string | T): T;
7+
8+
const a1 = f1(1, 2); // 1 | 2
9+
const a2 = f1(1, "hello"); // 1
10+
const a3 = f1(1, sn); // number
11+
const a4 = f1(undefined, "abc"); // undefined
12+
const a5 = f1("foo", "bar"); // "foo"
13+
const a6 = f1(true, false); // boolean
14+
const a7 = f1("hello", 1); // Error
15+
16+
declare function f2<T>(value: [string, T]): T;
17+
18+
var b1 = f2(["string", true]); // boolean
19+
20+
declare function f3<T>(x: string | false | T): T;
21+
22+
const c1 = f3(5); // 5
23+
const c2 = f3(sn); // number
24+
const c3 = f3(true); // true
25+
const c4 = f3(b); // true
26+
const c5 = f3("abc"); // never
27+
28+
declare function f4<T>(x: string & T): T;
29+
30+
const d1 = f4("abc");
31+
const d2 = f4(s);
32+
const d3 = f4(42); // Error
33+
34+
export interface Foo<T> {
35+
then<U>(f: (x: T) => U | Foo<U>, g: U): Foo<U>;
36+
}
37+
export interface Bar<T> {
38+
then<S>(f: (x: T) => S | Bar<S>, g: S): Bar<S>;
739
}
840

9-
var a1: number;
10-
var a1 = f(1, 2);
11-
var a2: number;
12-
var a2 = f(1, "hello");
13-
var a3: number;
14-
var a3 = f(1, a1 || "hello");
15-
var a4: any;
16-
var a4 = f(undefined, "abc");
17-
18-
function g<T>(value: [string, T]): T {
19-
return value[1];
41+
function qux(p1: Foo<void>, p2: Bar<void>) {
42+
p1 = p2;
2043
}
2144

22-
var b1: boolean;
23-
var b1 = g(["string", true]);
45+
// Repros from #32434
2446

25-
function h<T>(x: string|boolean|T): T {
26-
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
27-
}
47+
declare function foo<T>(x: T | Promise<T>): void;
48+
declare let x: false | Promise<true>;
49+
foo(x);
2850

29-
var c1: number;
30-
var c1 = h(5);
31-
var c2: string;
32-
var c2 = h("abc");
51+
declare function bar<T>(x: T, y: string | T): T;
52+
const y = bar(1, 2);
3353

3454

3555
//// [unionTypeInference.js]
36-
// Verify that inferences made *to* a type parameter in a union type are secondary
37-
// to inferences made directly to that type parameter
38-
function f(x, y) {
39-
return x;
40-
}
41-
var a1;
42-
var a1 = f(1, 2);
43-
var a2;
44-
var a2 = f(1, "hello");
45-
var a3;
46-
var a3 = f(1, a1 || "hello");
47-
var a4;
48-
var a4 = f(undefined, "abc");
49-
function g(value) {
50-
return value[1];
51-
}
52-
var b1;
53-
var b1 = g(["string", true]);
54-
function h(x) {
55-
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
56+
"use strict";
57+
exports.__esModule = true;
58+
var a1 = f1(1, 2); // 1 | 2
59+
var a2 = f1(1, "hello"); // 1
60+
var a3 = f1(1, sn); // number
61+
var a4 = f1(undefined, "abc"); // undefined
62+
var a5 = f1("foo", "bar"); // "foo"
63+
var a6 = f1(true, false); // boolean
64+
var a7 = f1("hello", 1); // Error
65+
var b1 = f2(["string", true]); // boolean
66+
var c1 = f3(5); // 5
67+
var c2 = f3(sn); // number
68+
var c3 = f3(true); // true
69+
var c4 = f3(b); // true
70+
var c5 = f3("abc"); // never
71+
var d1 = f4("abc");
72+
var d2 = f4(s);
73+
var d3 = f4(42); // Error
74+
function qux(p1, p2) {
75+
p1 = p2;
5676
}
57-
var c1;
58-
var c1 = h(5);
59-
var c2;
60-
var c2 = h("abc");
77+
foo(x);
78+
var y = bar(1, 2);

0 commit comments

Comments
 (0)