Skip to content

Commit 9c1796f

Browse files
Merge pull request #5607 from Microsoft/fixTypeApparentization
Only get the apparent type of a contextual type when needed
2 parents 75364b6 + b93394a commit 9c1796f

20 files changed

+518
-5
lines changed

src/compiler/checker.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7058,7 +7058,7 @@ namespace ts {
70587058
else if (operator === SyntaxKind.BarBarToken) {
70597059
// When an || expression has a contextual type, the operands are contextually typed by that type. When an ||
70607060
// expression has no contextual type, the right operand is contextually typed by the type of the left operand.
7061-
let type = getApparentTypeOfContextualType(binaryExpression);
7061+
let type = getContextualType(binaryExpression);
70627062
if (!type && node === binaryExpression.right) {
70637063
type = checkExpression(binaryExpression.left);
70647064
}
@@ -7173,7 +7173,7 @@ namespace ts {
71737173
// In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type.
71747174
function getContextualTypeForConditionalOperand(node: Expression): Type {
71757175
const conditional = <ConditionalExpression>node.parent;
7176-
return node === conditional.whenTrue || node === conditional.whenFalse ? getApparentTypeOfContextualType(conditional) : undefined;
7176+
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
71777177
}
71787178

71797179
function getContextualTypeForJsxExpression(expr: JsxExpression | JsxSpreadAttribute): Type {
@@ -7206,9 +7206,16 @@ namespace ts {
72067206
/**
72077207
* Woah! Do you really want to use this function?
72087208
*
7209-
* Unless you're trying to get the *non-apparent* type for a value-literal type,
7209+
* Unless you're trying to get the *non-apparent* type for a
7210+
* value-literal type or you're authoring relevant portions of this algorithm,
72107211
* you probably meant to use 'getApparentTypeOfContextualType'.
7211-
* Otherwise this is slightly less useful.
7212+
* Otherwise this may not be very useful.
7213+
*
7214+
* In cases where you *are* working on this function, you should understand
7215+
* when it is appropriate to use 'getContextualType' and 'getApparentTypeOfContetxualType'.
7216+
*
7217+
* - Use 'getContextualType' when you are simply going to propagate the result to the expression.
7218+
* - Use 'getApparentTypeOfContextualType' when you're going to need the members of the type.
72127219
*
72137220
* @param node the expression whose contextual type will be returned.
72147221
* @returns the contextual type of an expression.
@@ -7252,7 +7259,7 @@ namespace ts {
72527259
Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression);
72537260
return getContextualTypeForSubstitutionExpression(<TemplateExpression>parent.parent, node);
72547261
case SyntaxKind.ParenthesizedExpression:
7255-
return getApparentTypeOfContextualType(<ParenthesizedExpression>parent);
7262+
return getContextualType(<ParenthesizedExpression>parent);
72567263
case SyntaxKind.JsxExpression:
72577264
case SyntaxKind.JsxSpreadAttribute:
72587265
return getContextualTypeForJsxExpression(<JsxExpression>parent);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [stringLiteralTypesAndLogicalOrExpressions01.ts]
2+
3+
declare function myRandBool(): boolean;
4+
5+
let a: "foo" = "foo";
6+
let b = a || "foo";
7+
let c: "foo" = b;
8+
let d = b || "bar";
9+
let e: "foo" | "bar" = d;
10+
11+
12+
//// [stringLiteralTypesAndLogicalOrExpressions01.js]
13+
var a = "foo";
14+
var b = a || "foo";
15+
var c = b;
16+
var d = b || "bar";
17+
var e = d;
18+
19+
20+
//// [stringLiteralTypesAndLogicalOrExpressions01.d.ts]
21+
declare function myRandBool(): boolean;
22+
declare let a: "foo";
23+
declare let b: "foo";
24+
declare let c: "foo";
25+
declare let d: "foo" | "bar";
26+
declare let e: "foo" | "bar";
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndLogicalOrExpressions01.ts ===
2+
3+
declare function myRandBool(): boolean;
4+
>myRandBool : Symbol(myRandBool, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 0, 0))
5+
6+
let a: "foo" = "foo";
7+
>a : Symbol(a, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 3, 3))
8+
9+
let b = a || "foo";
10+
>b : Symbol(b, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 4, 3))
11+
>a : Symbol(a, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 3, 3))
12+
13+
let c: "foo" = b;
14+
>c : Symbol(c, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 5, 3))
15+
>b : Symbol(b, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 4, 3))
16+
17+
let d = b || "bar";
18+
>d : Symbol(d, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 6, 3))
19+
>b : Symbol(b, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 4, 3))
20+
21+
let e: "foo" | "bar" = d;
22+
>e : Symbol(e, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 7, 3))
23+
>d : Symbol(d, Decl(stringLiteralTypesAndLogicalOrExpressions01.ts, 6, 3))
24+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndLogicalOrExpressions01.ts ===
2+
3+
declare function myRandBool(): boolean;
4+
>myRandBool : () => boolean
5+
6+
let a: "foo" = "foo";
7+
>a : "foo"
8+
>"foo" : "foo"
9+
10+
let b = a || "foo";
11+
>b : "foo"
12+
>a || "foo" : "foo"
13+
>a : "foo"
14+
>"foo" : "foo"
15+
16+
let c: "foo" = b;
17+
>c : "foo"
18+
>b : "foo"
19+
20+
let d = b || "bar";
21+
>d : "foo" | "bar"
22+
>b || "bar" : "foo" | "bar"
23+
>b : "foo"
24+
>"bar" : "bar"
25+
26+
let e: "foo" | "bar" = d;
27+
>e : "foo" | "bar"
28+
>d : "foo" | "bar"
29+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [stringLiteralTypesAndParenthesizedExpressions01.ts]
2+
3+
declare function myRandBool(): boolean;
4+
5+
let a: "foo" = ("foo");
6+
let b: "foo" | "bar" = ("foo");
7+
let c: "foo" = (myRandBool ? "foo" : ("foo"));
8+
let d: "foo" | "bar" = (myRandBool ? "foo" : ("bar"));
9+
10+
11+
//// [stringLiteralTypesAndParenthesizedExpressions01.js]
12+
var a = ("foo");
13+
var b = ("foo");
14+
var c = (myRandBool ? "foo" : ("foo"));
15+
var d = (myRandBool ? "foo" : ("bar"));
16+
17+
18+
//// [stringLiteralTypesAndParenthesizedExpressions01.d.ts]
19+
declare function myRandBool(): boolean;
20+
declare let a: "foo";
21+
declare let b: "foo" | "bar";
22+
declare let c: "foo";
23+
declare let d: "foo" | "bar";
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndParenthesizedExpressions01.ts ===
2+
3+
declare function myRandBool(): boolean;
4+
>myRandBool : Symbol(myRandBool, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 0, 0))
5+
6+
let a: "foo" = ("foo");
7+
>a : Symbol(a, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 3, 3))
8+
9+
let b: "foo" | "bar" = ("foo");
10+
>b : Symbol(b, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 4, 3))
11+
12+
let c: "foo" = (myRandBool ? "foo" : ("foo"));
13+
>c : Symbol(c, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 5, 3))
14+
>myRandBool : Symbol(myRandBool, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 0, 0))
15+
16+
let d: "foo" | "bar" = (myRandBool ? "foo" : ("bar"));
17+
>d : Symbol(d, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 6, 3))
18+
>myRandBool : Symbol(myRandBool, Decl(stringLiteralTypesAndParenthesizedExpressions01.ts, 0, 0))
19+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndParenthesizedExpressions01.ts ===
2+
3+
declare function myRandBool(): boolean;
4+
>myRandBool : () => boolean
5+
6+
let a: "foo" = ("foo");
7+
>a : "foo"
8+
>("foo") : "foo"
9+
>"foo" : "foo"
10+
11+
let b: "foo" | "bar" = ("foo");
12+
>b : "foo" | "bar"
13+
>("foo") : "foo"
14+
>"foo" : "foo"
15+
16+
let c: "foo" = (myRandBool ? "foo" : ("foo"));
17+
>c : "foo"
18+
>(myRandBool ? "foo" : ("foo")) : "foo"
19+
>myRandBool ? "foo" : ("foo") : "foo"
20+
>myRandBool : () => boolean
21+
>"foo" : "foo"
22+
>("foo") : "foo"
23+
>"foo" : "foo"
24+
25+
let d: "foo" | "bar" = (myRandBool ? "foo" : ("bar"));
26+
>d : "foo" | "bar"
27+
>(myRandBool ? "foo" : ("bar")) : "foo" | "bar"
28+
>myRandBool ? "foo" : ("bar") : "foo" | "bar"
29+
>myRandBool : () => boolean
30+
>"foo" : "foo"
31+
>("bar") : "bar"
32+
>"bar" : "bar"
33+
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//// [stringLiteralTypesAsTypeParameterConstraint01.ts]
2+
3+
function foo<T extends "foo">(f: (x: T) => T) {
4+
return f;
5+
}
6+
7+
function bar<T extends "foo" | "bar">(f: (x: T) => T) {
8+
return f;
9+
}
10+
11+
let f = foo(x => x);
12+
let fResult = f("foo");
13+
14+
let g = foo((x => x));
15+
let gResult = g("foo");
16+
17+
let h = bar(x => x);
18+
let hResult = h("foo");
19+
hResult = h("bar");
20+
21+
//// [stringLiteralTypesAsTypeParameterConstraint01.js]
22+
function foo(f) {
23+
return f;
24+
}
25+
function bar(f) {
26+
return f;
27+
}
28+
var f = foo(function (x) { return x; });
29+
var fResult = f("foo");
30+
var g = foo((function (x) { return x; }));
31+
var gResult = g("foo");
32+
var h = bar(function (x) { return x; });
33+
var hResult = h("foo");
34+
hResult = h("bar");
35+
36+
37+
//// [stringLiteralTypesAsTypeParameterConstraint01.d.ts]
38+
declare function foo<T extends "foo">(f: (x: T) => T): (x: T) => T;
39+
declare function bar<T extends "foo" | "bar">(f: (x: T) => T): (x: T) => T;
40+
declare let f: (x: "foo") => "foo";
41+
declare let fResult: "foo";
42+
declare let g: (x: "foo") => "foo";
43+
declare let gResult: "foo";
44+
declare let h: (x: "foo" | "bar") => "foo" | "bar";
45+
declare let hResult: "foo" | "bar";
46+
47+
48+
//// [DtsFileErrors]
49+
50+
51+
tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTypeParameterConstraint01.d.ts(3,16): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
52+
tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTypeParameterConstraint01.d.ts(5,16): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
53+
54+
55+
==== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTypeParameterConstraint01.d.ts (2 errors) ====
56+
declare function foo<T extends "foo">(f: (x: T) => T): (x: T) => T;
57+
declare function bar<T extends "foo" | "bar">(f: (x: T) => T): (x: T) => T;
58+
declare let f: (x: "foo") => "foo";
59+
~~~~~~~~~~~~~~~~~~~
60+
!!! error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
61+
declare let fResult: "foo";
62+
declare let g: (x: "foo") => "foo";
63+
~~~~~~~~~~~~~~~~~~~
64+
!!! error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
65+
declare let gResult: "foo";
66+
declare let h: (x: "foo" | "bar") => "foo" | "bar";
67+
declare let hResult: "foo" | "bar";
68+
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAsTypeParameterConstraint01.ts ===
2+
3+
function foo<T extends "foo">(f: (x: T) => T) {
4+
>foo : Symbol(foo, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 0, 0))
5+
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 13))
6+
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 30))
7+
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 34))
8+
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 13))
9+
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 13))
10+
11+
return f;
12+
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 1, 30))
13+
}
14+
15+
function bar<T extends "foo" | "bar">(f: (x: T) => T) {
16+
>bar : Symbol(bar, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 3, 1))
17+
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 13))
18+
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 38))
19+
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 42))
20+
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 13))
21+
>T : Symbol(T, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 13))
22+
23+
return f;
24+
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 5, 38))
25+
}
26+
27+
let f = foo(x => x);
28+
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 9, 3))
29+
>foo : Symbol(foo, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 0, 0))
30+
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 9, 12))
31+
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 9, 12))
32+
33+
let fResult = f("foo");
34+
>fResult : Symbol(fResult, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 10, 3))
35+
>f : Symbol(f, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 9, 3))
36+
37+
let g = foo((x => x));
38+
>g : Symbol(g, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 12, 3))
39+
>foo : Symbol(foo, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 0, 0))
40+
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 12, 13))
41+
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 12, 13))
42+
43+
let gResult = g("foo");
44+
>gResult : Symbol(gResult, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 13, 3))
45+
>g : Symbol(g, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 12, 3))
46+
47+
let h = bar(x => x);
48+
>h : Symbol(h, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 15, 3))
49+
>bar : Symbol(bar, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 3, 1))
50+
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 15, 12))
51+
>x : Symbol(x, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 15, 12))
52+
53+
let hResult = h("foo");
54+
>hResult : Symbol(hResult, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 16, 3))
55+
>h : Symbol(h, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 15, 3))
56+
57+
hResult = h("bar");
58+
>hResult : Symbol(hResult, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 16, 3))
59+
>h : Symbol(h, Decl(stringLiteralTypesAsTypeParameterConstraint01.ts, 15, 3))
60+

0 commit comments

Comments
 (0)