Merge pull request #5607 from Microsoft/fixTypeApparentization

Only get the apparent type of a contextual type when needed
This commit is contained in:
Daniel Rosenwasser 2015-11-11 10:27:08 -08:00
commit 9c1796f714
20 changed files with 518 additions and 5 deletions

View file

@ -7058,7 +7058,7 @@ namespace ts {
else if (operator === SyntaxKind.BarBarToken) {
// When an || expression has a contextual type, the operands are contextually typed by that type. When an ||
// expression has no contextual type, the right operand is contextually typed by the type of the left operand.
let type = getApparentTypeOfContextualType(binaryExpression);
let type = getContextualType(binaryExpression);
if (!type && node === binaryExpression.right) {
type = checkExpression(binaryExpression.left);
}
@ -7173,7 +7173,7 @@ namespace ts {
// In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type.
function getContextualTypeForConditionalOperand(node: Expression): Type {
const conditional = <ConditionalExpression>node.parent;
return node === conditional.whenTrue || node === conditional.whenFalse ? getApparentTypeOfContextualType(conditional) : undefined;
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
}
function getContextualTypeForJsxExpression(expr: JsxExpression | JsxSpreadAttribute): Type {
@ -7206,9 +7206,16 @@ namespace ts {
/**
* Woah! Do you really want to use this function?
*
* Unless you're trying to get the *non-apparent* type for a value-literal type,
* Unless you're trying to get the *non-apparent* type for a
* value-literal type or you're authoring relevant portions of this algorithm,
* you probably meant to use 'getApparentTypeOfContextualType'.
* Otherwise this is slightly less useful.
* Otherwise this may not be very useful.
*
* In cases where you *are* working on this function, you should understand
* when it is appropriate to use 'getContextualType' and 'getApparentTypeOfContetxualType'.
*
* - Use 'getContextualType' when you are simply going to propagate the result to the expression.
* - Use 'getApparentTypeOfContextualType' when you're going to need the members of the type.
*
* @param node the expression whose contextual type will be returned.
* @returns the contextual type of an expression.
@ -7252,7 +7259,7 @@ namespace ts {
Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression);
return getContextualTypeForSubstitutionExpression(<TemplateExpression>parent.parent, node);
case SyntaxKind.ParenthesizedExpression:
return getApparentTypeOfContextualType(<ParenthesizedExpression>parent);
return getContextualType(<ParenthesizedExpression>parent);
case SyntaxKind.JsxExpression:
case SyntaxKind.JsxSpreadAttribute:
return getContextualTypeForJsxExpression(<JsxExpression>parent);

View file

@ -0,0 +1,26 @@
//// [stringLiteralTypesAndLogicalOrExpressions01.ts]
declare function myRandBool(): boolean;
let a: "foo" = "foo";
let b = a || "foo";
let c: "foo" = b;
let d = b || "bar";
let e: "foo" | "bar" = d;
//// [stringLiteralTypesAndLogicalOrExpressions01.js]
var a = "foo";
var b = a || "foo";
var c = b;
var d = b || "bar";
var e = d;
//// [stringLiteralTypesAndLogicalOrExpressions01.d.ts]
declare function myRandBool(): boolean;
declare let a: "foo";
declare let b: "foo";
declare let c: "foo";
declare let d: "foo" | "bar";
declare let e: "foo" | "bar";

View file

@ -0,0 +1,24 @@
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndLogicalOrExpressions01.ts ===
declare function myRandBool(): boolean;
>myRandBool : Symbol(myRandBool, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 0, 0))
let a: "foo" = "foo";
>a : Symbol(a, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 3, 3))
let b = a || "foo";
>b : Symbol(b, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 4, 3))
>a : Symbol(a, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 3, 3))
let c: "foo" = b;
>c : Symbol(c, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 5, 3))
>b : Symbol(b, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 4, 3))
let d = b || "bar";
>d : Symbol(d, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 6, 3))
>b : Symbol(b, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 4, 3))
let e: "foo" | "bar" = d;
>e : Symbol(e, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 7, 3))
>d : Symbol(d, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 6, 3))

View file

@ -0,0 +1,29 @@
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndLogicalOrExpressions01.ts ===
declare function myRandBool(): boolean;
>myRandBool : () => boolean
let a: "foo" = "foo";
>a : "foo"
>"foo" : "foo"
let b = a || "foo";
>b : "foo"
>a || "foo" : "foo"
>a : "foo"
>"foo" : "foo"
let c: "foo" = b;
>c : "foo"
>b : "foo"
let d = b || "bar";
>d : "foo" | "bar"
>b || "bar" : "foo" | "bar"
>b : "foo"
>"bar" : "bar"
let e: "foo" | "bar" = d;
>e : "foo" | "bar"
>d : "foo" | "bar"

View file

@ -0,0 +1,23 @@
//// [stringLiteralTypesAndParenthesizedExpressions01.ts]
declare function myRandBool(): boolean;
let a: "foo" = ("foo");
let b: "foo" | "bar" = ("foo");
let c: "foo" = (myRandBool ? "foo" : ("foo"));
let d: "foo" | "bar" = (myRandBool ? "foo" : ("bar"));
//// [stringLiteralTypesAndParenthesizedExpressions01.js]
var a = ("foo");
var b = ("foo");
var c = (myRandBool ? "foo" : ("foo"));
var d = (myRandBool ? "foo" : ("bar"));
//// [stringLiteralTypesAndParenthesizedExpressions01.d.ts]
declare function myRandBool(): boolean;
declare let a: "foo";
declare let b: "foo" | "bar";
declare let c: "foo";
declare let d: "foo" | "bar";

View file

@ -0,0 +1,19 @@
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndParenthesizedExpressions01.ts ===
declare function myRandBool(): boolean;
>myRandBool : Symbol(myRandBool, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 0, 0))
let a: "foo" = ("foo");
>a : Symbol(a, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 3, 3))
let b: "foo" | "bar" = ("foo");
>b : Symbol(b, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 4, 3))
let c: "foo" = (myRandBool ? "foo" : ("foo"));
>c : Symbol(c, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 5, 3))
>myRandBool : Symbol(myRandBool, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 0, 0))
let d: "foo" | "bar" = (myRandBool ? "foo" : ("bar"));
>d : Symbol(d, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 6, 3))
>myRandBool : Symbol(myRandBool, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 0, 0))

View file

@ -0,0 +1,33 @@
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndParenthesizedExpressions01.ts ===
declare function myRandBool(): boolean;
>myRandBool : () => boolean
let a: "foo" = ("foo");
>a : "foo"
>("foo") : "foo"
>"foo" : "foo"
let b: "foo" | "bar" = ("foo");
>b : "foo" | "bar"
>("foo") : "foo"
>"foo" : "foo"
let c: "foo" = (myRandBool ? "foo" : ("foo"));
>c : "foo"
>(myRandBool ? "foo" : ("foo")) : "foo"
>myRandBool ? "foo" : ("foo") : "foo"
>myRandBool : () => boolean
>"foo" : "foo"
>("foo") : "foo"
>"foo" : "foo"
let d: "foo" | "bar" = (myRandBool ? "foo" : ("bar"));
>d : "foo" | "bar"
>(myRandBool ? "foo" : ("bar")) : "foo" | "bar"
>myRandBool ? "foo" : ("bar") : "foo" | "bar"
>myRandBool : () => boolean
>"foo" : "foo"
>("bar") : "bar"
>"bar" : "bar"

View file

@ -0,0 +1,68 @@
//// [stringLiteralTypesAsTypeParameterConstraint01.ts]
function foo<T extends "foo">(f: (x: T) => T) {
return f;
}
function bar<T extends "foo" | "bar">(f: (x: T) => T) {
return f;
}
let f = foo(x => x);
let fResult = f("foo");
let g = foo((x => x));
let gResult = g("foo");
let h = bar(x => x);
let hResult = h("foo");
hResult = h("bar");
//// [stringLiteralTypesAsTypeParameterConstraint01.js]
function foo(f) {
return f;
}
function bar(f) {
return f;
}
var f = foo(function (x) { return x; });
var fResult = f("foo");
var g = foo((function (x) { return x; }));
var gResult = g("foo");
var h = bar(function (x) { return x; });
var hResult = h("foo");
hResult = h("bar");
//// [stringLiteralTypesAsTypeParameterConstraint01.d.ts]
declare function foo<T extends "foo">(f: (x: T) => T): (x: T) => T;
declare function bar<T extends "foo" | "bar">(f: (x: T) => T): (x: T) => T;
declare let f: (x: "foo") => "foo";
declare let fResult: "foo";
declare let g: (x: "foo") => "foo";
declare let gResult: "foo";
declare let h: (x: "foo" | "bar") => "foo" | "bar";
declare let hResult: "foo" | "bar";
//// [DtsFileErrors]
tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTypeParameterConstraint01.d.ts(3,16): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTypeParameterConstraint01.d.ts(5,16): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
==== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTypeParameterConstraint01.d.ts (2 errors) ====
declare function foo<T extends "foo">(f: (x: T) => T): (x: T) => T;
declare function bar<T extends "foo" | "bar">(f: (x: T) => T): (x: T) => T;
declare let f: (x: "foo") => "foo";
~~~~~~~~~~~~~~~~~~~
!!! error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
declare let fResult: "foo";
declare let g: (x: "foo") => "foo";
~~~~~~~~~~~~~~~~~~~
!!! error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
declare let gResult: "foo";
declare let h: (x: "foo" | "bar") => "foo" | "bar";
declare let hResult: "foo" | "bar";

View file

@ -0,0 +1,60 @@
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTypeParameterConstraint01.ts ===
function foo<T extends "foo">(f: (x: T) => T) {
>foo : Symbol(foo, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 0, 0))
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 13))
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 30))
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 34))
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 13))
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 13))
return f;
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 30))
}
function bar<T extends "foo" | "bar">(f: (x: T) => T) {
>bar : Symbol(bar, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 3, 1))
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 13))
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 38))
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 42))
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 13))
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 13))
return f;
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 38))
}
let f = foo(x => x);
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 9, 3))
>foo : Symbol(foo, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 0, 0))
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 9, 12))
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 9, 12))
let fResult = f("foo");
>fResult : Symbol(fResult, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 10, 3))
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 9, 3))
let g = foo((x => x));
>g : Symbol(g, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 12, 3))
>foo : Symbol(foo, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 0, 0))
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 12, 13))
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 12, 13))
let gResult = g("foo");
>gResult : Symbol(gResult, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 13, 3))
>g : Symbol(g, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 12, 3))
let h = bar(x => x);
>h : Symbol(h, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 15, 3))
>bar : Symbol(bar, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 3, 1))
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 15, 12))
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 15, 12))
let hResult = h("foo");
>hResult : Symbol(hResult, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 16, 3))
>h : Symbol(h, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 15, 3))
hResult = h("bar");
>hResult : Symbol(hResult, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 16, 3))
>h : Symbol(h, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 15, 3))

View file

@ -0,0 +1,76 @@
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTypeParameterConstraint01.ts ===
function foo<T extends "foo">(f: (x: T) => T) {
>foo : <T extends "foo">(f: (x: T) => T) => (x: T) => T
>T : T
>f : (x: T) => T
>x : T
>T : T
>T : T
return f;
>f : (x: T) => T
}
function bar<T extends "foo" | "bar">(f: (x: T) => T) {
>bar : <T extends "foo" | "bar">(f: (x: T) => T) => (x: T) => T
>T : T
>f : (x: T) => T
>x : T
>T : T
>T : T
return f;
>f : (x: T) => T
}
let f = foo(x => x);
>f : (x: "foo") => "foo"
>foo(x => x) : (x: "foo") => "foo"
>foo : <T extends "foo">(f: (x: T) => T) => (x: T) => T
>x => x : (x: "foo") => "foo"
>x : "foo"
>x : "foo"
let fResult = f("foo");
>fResult : "foo"
>f("foo") : "foo"
>f : (x: "foo") => "foo"
>"foo" : "foo"
let g = foo((x => x));
>g : (x: "foo") => "foo"
>foo((x => x)) : (x: "foo") => "foo"
>foo : <T extends "foo">(f: (x: T) => T) => (x: T) => T
>(x => x) : (x: "foo") => "foo"
>x => x : (x: "foo") => "foo"
>x : "foo"
>x : "foo"
let gResult = g("foo");
>gResult : "foo"
>g("foo") : "foo"
>g : (x: "foo") => "foo"
>"foo" : "foo"
let h = bar(x => x);
>h : (x: "foo" | "bar") => "foo" | "bar"
>bar(x => x) : (x: "foo" | "bar") => "foo" | "bar"
>bar : <T extends "foo" | "bar">(f: (x: T) => T) => (x: T) => T
>x => x : (x: "foo" | "bar") => "foo" | "bar"
>x : "foo" | "bar"
>x : "foo" | "bar"
let hResult = h("foo");
>hResult : "foo" | "bar"
>h("foo") : "foo" | "bar"
>h : (x: "foo" | "bar") => "foo" | "bar"
>"foo" : "foo"
hResult = h("bar");
>hResult = h("bar") : "foo" | "bar"
>hResult : "foo" | "bar"
>h("bar") : "foo" | "bar"
>h : (x: "foo" | "bar") => "foo" | "bar"
>"bar" : "bar"

View file

@ -0,0 +1,15 @@
tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTypeParameterConstraint02.ts(6,13): error TS2345: Argument of type '(y: "foo" | "bar") => string' is not assignable to parameter of type '(x: "foo") => "foo"'.
Type 'string' is not assignable to type '"foo"'.
==== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTypeParameterConstraint02.ts (1 errors) ====
function foo<T extends "foo">(f: (x: T) => T) {
return f;
}
let f = foo((y: "foo" | "bar") => y === "foo" ? y : "foo");
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '(y: "foo" | "bar") => string' is not assignable to parameter of type '(x: "foo") => "foo"'.
!!! error TS2345: Type 'string' is not assignable to type '"foo"'.
let fResult = f("foo");

View file

@ -0,0 +1,21 @@
//// [stringLiteralTypesAsTypeParameterConstraint02.ts]
function foo<T extends "foo">(f: (x: T) => T) {
return f;
}
let f = foo((y: "foo" | "bar") => y === "foo" ? y : "foo");
let fResult = f("foo");
//// [stringLiteralTypesAsTypeParameterConstraint02.js]
function foo(f) {
return f;
}
var f = foo(function (y) { return y === "foo" ? y : "foo"; });
var fResult = f("foo");
//// [stringLiteralTypesAsTypeParameterConstraint02.d.ts]
declare function foo<T extends "foo">(f: (x: T) => T): (x: T) => T;
declare let f: any;
declare let fResult: any;

View file

@ -0,0 +1,18 @@
//// [stringLiteralTypesOverloads04.ts]
declare function f(x: (p: "foo" | "bar") => "foo");
f(y => {
let z = y = "foo";
return z;
})
//// [stringLiteralTypesOverloads04.js]
f(function (y) {
var z = y = "foo";
return z;
});
//// [stringLiteralTypesOverloads04.d.ts]
declare function f(x: (p: "foo" | "bar") => "foo"): any;

View file

@ -0,0 +1,19 @@
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesOverloads04.ts ===
declare function f(x: (p: "foo" | "bar") => "foo");
>f : Symbol(f, Decl(stringLiteralTypesOverloads04.ts, 0, 0))
>x : Symbol(x, Decl(stringLiteralTypesOverloads04.ts, 1, 19))
>p : Symbol(p, Decl(stringLiteralTypesOverloads04.ts, 1, 23))
f(y => {
>f : Symbol(f, Decl(stringLiteralTypesOverloads04.ts, 0, 0))
>y : Symbol(y, Decl(stringLiteralTypesOverloads04.ts, 3, 2))
let z = y = "foo";
>z : Symbol(z, Decl(stringLiteralTypesOverloads04.ts, 4, 7))
>y : Symbol(y, Decl(stringLiteralTypesOverloads04.ts, 3, 2))
return z;
>z : Symbol(z, Decl(stringLiteralTypesOverloads04.ts, 4, 7))
})

View file

@ -0,0 +1,23 @@
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesOverloads04.ts ===
declare function f(x: (p: "foo" | "bar") => "foo");
>f : (x: (p: "foo" | "bar") => "foo") => any
>x : (p: "foo" | "bar") => "foo"
>p : "foo" | "bar"
f(y => {
>f(y => { let z = y = "foo"; return z;}) : any
>f : (x: (p: "foo" | "bar") => "foo") => any
>y => { let z = y = "foo"; return z;} : (y: "foo" | "bar") => "foo"
>y : "foo" | "bar"
let z = y = "foo";
>z : "foo"
>y = "foo" : "foo"
>y : "foo" | "bar"
>"foo" : "foo"
return z;
>z : "foo"
})

View file

@ -0,0 +1,9 @@
// @declaration: true
declare function myRandBool(): boolean;
let a: "foo" = "foo";
let b = a || "foo";
let c: "foo" = b;
let d = b || "bar";
let e: "foo" | "bar" = d;

View file

@ -0,0 +1,8 @@
// @declaration: true
declare function myRandBool(): boolean;
let a: "foo" = ("foo");
let b: "foo" | "bar" = ("foo");
let c: "foo" = (myRandBool ? "foo" : ("foo"));
let d: "foo" | "bar" = (myRandBool ? "foo" : ("bar"));

View file

@ -0,0 +1,19 @@
// @declaration: true
function foo<T extends "foo">(f: (x: T) => T) {
return f;
}
function bar<T extends "foo" | "bar">(f: (x: T) => T) {
return f;
}
let f = foo(x => x);
let fResult = f("foo");
let g = foo((x => x));
let gResult = g("foo");
let h = bar(x => x);
let hResult = h("foo");
hResult = h("bar");

View file

@ -0,0 +1,8 @@
// @declaration: true
function foo<T extends "foo">(f: (x: T) => T) {
return f;
}
let f = foo((y: "foo" | "bar") => y === "foo" ? y : "foo");
let fResult = f("foo");

View file

@ -0,0 +1,8 @@
// @declaration: true
declare function f(x: (p: "foo" | "bar") => "foo");
f(y => {
let z = y = "foo";
return z;
})