Skip to content

Commit

Permalink
Merge pull request #32460 from microsoft/fix32434
Browse files Browse the repository at this point in the history
Improve type inference for types like 'T | Promise<T>'
  • Loading branch information
ahejlsberg authored Jul 23, 2019
2 parents d982014 + 5646856 commit 9ec71c3
Show file tree
Hide file tree
Showing 7 changed files with 630 additions and 325 deletions.
193 changes: 133 additions & 60 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var e1: number | string | boolean;
>e1 : string | number | boolean

f1(a1); // string
>f1(a1) : string
>f1(a1) : unknown
>f1 : <T>(x: string | T) => T
>a1 : string

Expand Down
79 changes: 51 additions & 28 deletions tests/baselines/reference/unionTypeInference.errors.txt
Original file line number Diff line number Diff line change
@@ -1,38 +1,61 @@
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'.
tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(13,24): error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(31,15): error TS2345: Argument of type '42' is not assignable to parameter of type 'never'.


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

function f<T>(x: T, y: string|T): T {
return x;
declare function f1<T>(x: T, y: string | T): T;

const a1 = f1(1, 2); // 1 | 2
const a2 = f1(1, "hello"); // 1
const a3 = f1(1, sn); // number
const a4 = f1(undefined, "abc"); // undefined
const a5 = f1("foo", "bar"); // "foo"
const a6 = f1(true, false); // boolean
const a7 = f1("hello", 1); // Error
~
!!! error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.

declare function f2<T>(value: [string, T]): T;

var b1 = f2(["string", true]); // boolean

declare function f3<T>(x: string | false | T): T;

const c1 = f3(5); // 5
const c2 = f3(sn); // number
const c3 = f3(true); // true
const c4 = f3(b); // true
const c5 = f3("abc"); // never

declare function f4<T>(x: string & T): T;

const d1 = f4("abc");
const d2 = f4(s);
const d3 = f4(42); // Error
~~
!!! error TS2345: Argument of type '42' is not assignable to parameter of type 'never'.

export interface Foo<T> {
then<U>(f: (x: T) => U | Foo<U>, g: U): Foo<U>;
}
export interface Bar<T> {
then<S>(f: (x: T) => S | Bar<S>, g: S): Bar<S>;
}

var a1: number;
var a1 = f(1, 2);
~
!!! error TS2345: Argument of type '2' is not assignable to parameter of type 'string | 1'.
var a2: number;
var a2 = f(1, "hello");
var a3: number;
var a3 = f(1, a1 || "hello");
var a4: any;
var a4 = f(undefined, "abc");

function g<T>(value: [string, T]): T {
return value[1];
function qux(p1: Foo<void>, p2: Bar<void>) {
p1 = p2;
}

var b1: boolean;
var b1 = g(["string", true]);
// Repros from #32434

function h<T>(x: string|boolean|T): T {
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
}
declare function foo<T>(x: T | Promise<T>): void;
declare let x: false | Promise<true>;
foo(x);

var c1: number;
var c1 = h(5);
var c2: string;
var c2 = h("abc");
declare function bar<T>(x: T, y: string | T): T;
const y = bar(1, 2);

114 changes: 66 additions & 48 deletions tests/baselines/reference/unionTypeInference.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,78 @@
//// [unionTypeInference.ts]
// Verify that inferences made *to* a type parameter in a union type are secondary
// to inferences made directly to that type parameter
declare const b: boolean;
declare const s: string;
declare const sn: string | number;

function f<T>(x: T, y: string|T): T {
return x;
declare function f1<T>(x: T, y: string | T): T;

const a1 = f1(1, 2); // 1 | 2
const a2 = f1(1, "hello"); // 1
const a3 = f1(1, sn); // number
const a4 = f1(undefined, "abc"); // undefined
const a5 = f1("foo", "bar"); // "foo"
const a6 = f1(true, false); // boolean
const a7 = f1("hello", 1); // Error

declare function f2<T>(value: [string, T]): T;

var b1 = f2(["string", true]); // boolean

declare function f3<T>(x: string | false | T): T;

const c1 = f3(5); // 5
const c2 = f3(sn); // number
const c3 = f3(true); // true
const c4 = f3(b); // true
const c5 = f3("abc"); // never

declare function f4<T>(x: string & T): T;

const d1 = f4("abc");
const d2 = f4(s);
const d3 = f4(42); // Error

export interface Foo<T> {
then<U>(f: (x: T) => U | Foo<U>, g: U): Foo<U>;
}
export interface Bar<T> {
then<S>(f: (x: T) => S | Bar<S>, g: S): Bar<S>;
}

var a1: number;
var a1 = f(1, 2);
var a2: number;
var a2 = f(1, "hello");
var a3: number;
var a3 = f(1, a1 || "hello");
var a4: any;
var a4 = f(undefined, "abc");

function g<T>(value: [string, T]): T {
return value[1];
function qux(p1: Foo<void>, p2: Bar<void>) {
p1 = p2;
}

var b1: boolean;
var b1 = g(["string", true]);
// Repros from #32434

function h<T>(x: string|boolean|T): T {
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
}
declare function foo<T>(x: T | Promise<T>): void;
declare let x: false | Promise<true>;
foo(x);

var c1: number;
var c1 = h(5);
var c2: string;
var c2 = h("abc");
declare function bar<T>(x: T, y: string | T): T;
const y = bar(1, 2);


//// [unionTypeInference.js]
// Verify that inferences made *to* a type parameter in a union type are secondary
// to inferences made directly to that type parameter
function f(x, y) {
return x;
}
var a1;
var a1 = f(1, 2);
var a2;
var a2 = f(1, "hello");
var a3;
var a3 = f(1, a1 || "hello");
var a4;
var a4 = f(undefined, "abc");
function g(value) {
return value[1];
}
var b1;
var b1 = g(["string", true]);
function h(x) {
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
"use strict";
exports.__esModule = true;
var a1 = f1(1, 2); // 1 | 2
var a2 = f1(1, "hello"); // 1
var a3 = f1(1, sn); // number
var a4 = f1(undefined, "abc"); // undefined
var a5 = f1("foo", "bar"); // "foo"
var a6 = f1(true, false); // boolean
var a7 = f1("hello", 1); // Error
var b1 = f2(["string", true]); // boolean
var c1 = f3(5); // 5
var c2 = f3(sn); // number
var c3 = f3(true); // true
var c4 = f3(b); // true
var c5 = f3("abc"); // never
var d1 = f4("abc");
var d2 = f4(s);
var d3 = f4(42); // Error
function qux(p1, p2) {
p1 = p2;
}
var c1;
var c1 = h(5);
var c2;
var c2 = h("abc");
foo(x);
var y = bar(1, 2);
Loading

0 comments on commit 9ec71c3

Please sign in to comment.