Skip to content

Only get the apparent type of a contextual type when needed #5607

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 11, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6966,7 +6966,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);
}
Expand Down Expand Up @@ -7081,7 +7081,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 {
Expand Down Expand Up @@ -7114,9 +7114,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.
Expand Down Expand Up @@ -7160,7 +7167,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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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";
Original file line number Diff line number Diff line change
@@ -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))

Original file line number Diff line number Diff line change
@@ -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"

Original file line number Diff line number Diff line change
@@ -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";
Original file line number Diff line number Diff line change
@@ -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))

Original file line number Diff line number Diff line change
@@ -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"

Original file line number Diff line number Diff line change
@@ -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";

Original file line number Diff line number Diff line change
@@ -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))

Loading