Skip to content

Commit 69855e2

Browse files
committed
Allow boolean literals to be generated from contextual types again (microsoft#21503)
* Allow boolean literals to be generated from contextual types again * Update fourslash test
1 parent 1a6d6ad commit 69855e2

File tree

93 files changed

+614
-316
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+614
-316
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18960,13 +18960,9 @@ namespace ts {
1896018960

1896118961
function isLiteralOfContextualType(candidateType: Type, contextualType: Type): boolean {
1896218962
if (contextualType) {
18963-
if (contextualType.flags & TypeFlags.UnionOrIntersection && !(contextualType.flags & TypeFlags.Boolean)) {
18964-
// If the contextual type is a union containing both of the 'true' and 'false' types we
18965-
// don't consider it a literal context for boolean literals.
18963+
if (contextualType.flags & TypeFlags.UnionOrIntersection) {
1896618964
const types = (<UnionType>contextualType).types;
18967-
return some(types, t =>
18968-
!(t.flags & TypeFlags.BooleanLiteral && containsType(types, trueType) && containsType(types, falseType)) &&
18969-
isLiteralOfContextualType(candidateType, t));
18965+
return some(types, t => isLiteralOfContextualType(candidateType, t));
1897018966
}
1897118967
if (contextualType.flags & TypeFlags.TypeVariable) {
1897218968
// If the contextual type is a type variable constrained to a primitive type, consider

tests/baselines/reference/argumentExpressionContextualTyping.types

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ var o1: { x: [string, number], y: { c: boolean, d: string, e: number } } = { x:
5151
>c : boolean
5252
>d : string
5353
>e : number
54-
>{ x: ["string", 1], y: { c: true, d: "world", e: 3 } } : { x: [string, number]; y: { c: boolean; d: string; e: number; }; }
54+
>{ x: ["string", 1], y: { c: true, d: "world", e: 3 } } : { x: [string, number]; y: { c: true; d: string; e: number; }; }
5555
>x : [string, number]
5656
>["string", 1] : [string, number]
5757
>"string" : "string"
5858
>1 : 1
59-
>y : { c: boolean; d: string; e: number; }
60-
>{ c: true, d: "world", e: 3 } : { c: boolean; d: string; e: number; }
61-
>c : boolean
59+
>y : { c: true; d: string; e: number; }
60+
>{ c: true, d: "world", e: 3 } : { c: true; d: string; e: number; }
61+
>c : true
6262
>true : true
6363
>d : string
6464
>"world" : "world"
@@ -96,7 +96,7 @@ var array = ["string", 1, true];
9696

9797
var tuple: [string, number, boolean] = ["string", 1, true];
9898
>tuple : [string, number, boolean]
99-
>["string", 1, true] : [string, number, boolean]
99+
>["string", 1, true] : [string, number, true]
100100
>"string" : "string"
101101
>1 : 1
102102
>true : true
@@ -109,7 +109,7 @@ baz(tuple);
109109
baz(["string", 1, true]);
110110
>baz(["string", 1, true]) : void
111111
>baz : (x: [string, number, boolean]) => void
112-
>["string", 1, true] : [string, number, boolean]
112+
>["string", 1, true] : [string, number, true]
113113
>"string" : "string"
114114
>1 : 1
115115
>true : true

tests/baselines/reference/arrayBestCommonTypes.types

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -255,15 +255,15 @@ module EmptyTypes {
255255
>x : boolean
256256
>y : base
257257
>base : base
258-
>[{ x: true, y: new derived() }, { x: false, y: new base() }] : { x: boolean; y: derived; }[]
259-
>{ x: true, y: new derived() } : { x: boolean; y: derived; }
260-
>x : boolean
258+
>[{ x: true, y: new derived() }, { x: false, y: new base() }] : ({ x: true; y: derived; } | { x: false; y: base; })[]
259+
>{ x: true, y: new derived() } : { x: true; y: derived; }
260+
>x : true
261261
>true : true
262262
>y : derived
263263
>new derived() : derived
264264
>derived : typeof derived
265-
>{ x: false, y: new base() } : { x: boolean; y: base; }
266-
>x : boolean
265+
>{ x: false, y: new base() } : { x: false; y: base; }
266+
>x : false
267267
>false : false
268268
>y : base
269269
>new base() : base
@@ -658,15 +658,15 @@ module NonEmptyTypes {
658658
>x : boolean
659659
>y : base
660660
>base : base
661-
>[{ x: true, y: new derived() }, { x: false, y: new base() }] : { x: boolean; y: base; }[]
662-
>{ x: true, y: new derived() } : { x: boolean; y: derived; }
663-
>x : boolean
661+
>[{ x: true, y: new derived() }, { x: false, y: new base() }] : ({ x: true; y: derived; } | { x: false; y: base; })[]
662+
>{ x: true, y: new derived() } : { x: true; y: derived; }
663+
>x : true
664664
>true : true
665665
>y : derived
666666
>new derived() : derived
667667
>derived : typeof derived
668-
>{ x: false, y: new base() } : { x: boolean; y: base; }
669-
>x : boolean
668+
>{ x: false, y: new base() } : { x: false; y: base; }
669+
>x : false
670670
>false : false
671671
>y : base
672672
>new base() : base

tests/baselines/reference/assignToFn.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ module M {
1313
var x:I={ f:function(n) { return true; } };
1414
>x : I
1515
>I : I
16-
>{ f:function(n) { return true; } } : { f: (n: number) => boolean; }
17-
>f : (n: number) => boolean
18-
>function(n) { return true; } : (n: number) => boolean
16+
>{ f:function(n) { return true; } } : { f: (n: number) => true; }
17+
>f : (n: number) => true
18+
>function(n) { return true; } : (n: number) => true
1919
>n : number
2020
>true : true
2121

tests/baselines/reference/assignmentTypeNarrowing.types

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ x; // string
1212
>x : string
1313

1414
[x] = [true];
15-
>[x] = [true] : [boolean]
15+
>[x] = [true] : [true]
1616
>[x] : [string | number | boolean | RegExp]
1717
>x : string | number | boolean | RegExp
18-
>[true] : [boolean]
18+
>[true] : [true]
1919
>true : true
2020

2121
x; // boolean
22-
>x : boolean
22+
>x : true
2323

2424
[x = ""] = [1];
2525
>[x = ""] = [1] : [number]
@@ -34,16 +34,16 @@ x; // string | number
3434
>x : string | number
3535

3636
({x} = {x: true});
37-
>({x} = {x: true}) : { x: boolean; }
38-
>{x} = {x: true} : { x: boolean; }
37+
>({x} = {x: true}) : { x: true; }
38+
>{x} = {x: true} : { x: true; }
3939
>{x} : { x: string | number | boolean | RegExp; }
4040
>x : string | number | boolean | RegExp
41-
>{x: true} : { x: boolean; }
42-
>x : boolean
41+
>{x: true} : { x: true; }
42+
>x : true
4343
>true : true
4444

4545
x; // boolean
46-
>x : boolean
46+
>x : true
4747

4848
({y: x} = {y: 1});
4949
>({y: x} = {y: 1}) : { y: number; }
@@ -59,16 +59,16 @@ x; // number
5959
>x : number
6060

6161
({x = ""} = {x: true});
62-
>({x = ""} = {x: true}) : { x?: boolean; }
63-
>{x = ""} = {x: true} : { x?: boolean; }
62+
>({x = ""} = {x: true}) : { x?: true; }
63+
>{x = ""} = {x: true} : { x?: true; }
6464
>{x = ""} : { x?: string | number | boolean | RegExp; }
6565
>x : string | number | boolean | RegExp
66-
>{x: true} : { x?: boolean; }
67-
>x : boolean
66+
>{x: true} : { x?: true; }
67+
>x : true
6868
>true : true
6969

7070
x; // string | boolean
71-
>x : string | boolean
71+
>x : string | true
7272

7373
({y: x = /a/} = {y: 1});
7474
>({y: x = /a/} = {y: 1}) : { y?: number; }

tests/baselines/reference/asyncFunctionReturnType.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ async function fAsyncExplicit(): Promise<[number, boolean]> {
1515

1616
// This is contextually typed as a tuple.
1717
return [1, true];
18-
>[1, true] : [number, boolean]
18+
>[1, true] : [number, true]
1919
>1 : 1
2020
>true : true
2121
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//// [booleanLiteralsContextuallyTypedFromUnion.tsx]
2+
interface A { isIt: true; text: string; }
3+
interface B { isIt: false; value: number; }
4+
type C = A | B;
5+
const isIt = Math.random() > 0.5;
6+
const c: C = isIt ? { isIt, text: 'hey' } : { isIt, value: 123 };
7+
const cc: C = isIt ? { isIt: isIt, text: 'hey' } : { isIt: isIt, value: 123 };
8+
9+
type ComponentProps =
10+
| {
11+
optionalBool: true;
12+
mandatoryFn: () => void;
13+
}
14+
| {
15+
optionalBool: false;
16+
};
17+
18+
let Funk = (_props: ComponentProps) => <div>Hello</div>;
19+
20+
let Fail1 = () => <Funk mandatoryFn={() => { }} optionalBool={true} />
21+
let Fail2 = () => <Funk mandatoryFn={() => { }} optionalBool={true as true} />
22+
let True = true as true;
23+
let Fail3 = () => <Funk mandatoryFn={() => { }} optionalBool={True} />
24+
let attrs2 = { optionalBool: true as true, mandatoryFn: () => { } }
25+
let Success = () => <Funk {...attrs2} />
26+
27+
//// [booleanLiteralsContextuallyTypedFromUnion.jsx]
28+
"use strict";
29+
var isIt = Math.random() > 0.5;
30+
var c = isIt ? { isIt: isIt, text: 'hey' } : { isIt: isIt, value: 123 };
31+
var cc = isIt ? { isIt: isIt, text: 'hey' } : { isIt: isIt, value: 123 };
32+
var Funk = function (_props) { return <div>Hello</div>; };
33+
var Fail1 = function () { return <Funk mandatoryFn={function () { }} optionalBool={true}/>; };
34+
var Fail2 = function () { return <Funk mandatoryFn={function () { }} optionalBool={true}/>; };
35+
var True = true;
36+
var Fail3 = function () { return <Funk mandatoryFn={function () { }} optionalBool={True}/>; };
37+
var attrs2 = { optionalBool: true, mandatoryFn: function () { } };
38+
var Success = function () { return <Funk {...attrs2}/>; };
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
=== tests/cases/compiler/booleanLiteralsContextuallyTypedFromUnion.tsx ===
2+
interface A { isIt: true; text: string; }
3+
>A : Symbol(A, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 0, 0))
4+
>isIt : Symbol(A.isIt, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 0, 13))
5+
>text : Symbol(A.text, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 0, 25))
6+
7+
interface B { isIt: false; value: number; }
8+
>B : Symbol(B, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 0, 41))
9+
>isIt : Symbol(B.isIt, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 1, 13))
10+
>value : Symbol(B.value, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 1, 26))
11+
12+
type C = A | B;
13+
>C : Symbol(C, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 1, 43))
14+
>A : Symbol(A, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 0, 0))
15+
>B : Symbol(B, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 0, 41))
16+
17+
const isIt = Math.random() > 0.5;
18+
>isIt : Symbol(isIt, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 3, 5))
19+
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
20+
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
21+
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
22+
23+
const c: C = isIt ? { isIt, text: 'hey' } : { isIt, value: 123 };
24+
>c : Symbol(c, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 4, 5))
25+
>C : Symbol(C, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 1, 43))
26+
>isIt : Symbol(isIt, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 3, 5))
27+
>isIt : Symbol(isIt, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 4, 21))
28+
>text : Symbol(text, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 4, 27))
29+
>isIt : Symbol(isIt, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 4, 45))
30+
>value : Symbol(value, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 4, 51))
31+
32+
const cc: C = isIt ? { isIt: isIt, text: 'hey' } : { isIt: isIt, value: 123 };
33+
>cc : Symbol(cc, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 5, 5))
34+
>C : Symbol(C, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 1, 43))
35+
>isIt : Symbol(isIt, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 3, 5))
36+
>isIt : Symbol(isIt, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 5, 22))
37+
>isIt : Symbol(isIt, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 3, 5))
38+
>text : Symbol(text, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 5, 34))
39+
>isIt : Symbol(isIt, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 5, 52))
40+
>isIt : Symbol(isIt, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 3, 5))
41+
>value : Symbol(value, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 5, 64))
42+
43+
type ComponentProps =
44+
>ComponentProps : Symbol(ComponentProps, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 5, 78))
45+
46+
| {
47+
optionalBool: true;
48+
>optionalBool : Symbol(optionalBool, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 8, 7))
49+
50+
mandatoryFn: () => void;
51+
>mandatoryFn : Symbol(mandatoryFn, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 9, 27))
52+
}
53+
| {
54+
optionalBool: false;
55+
>optionalBool : Symbol(optionalBool, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 12, 7))
56+
57+
};
58+
59+
let Funk = (_props: ComponentProps) => <div>Hello</div>;
60+
>Funk : Symbol(Funk, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 16, 3))
61+
>_props : Symbol(_props, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 16, 12))
62+
>ComponentProps : Symbol(ComponentProps, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 5, 78))
63+
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
64+
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
65+
66+
let Fail1 = () => <Funk mandatoryFn={() => { }} optionalBool={true} />
67+
>Fail1 : Symbol(Fail1, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 18, 3))
68+
>Funk : Symbol(Funk, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 16, 3))
69+
>mandatoryFn : Symbol(mandatoryFn, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 18, 23))
70+
>optionalBool : Symbol(optionalBool, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 18, 47))
71+
72+
let Fail2 = () => <Funk mandatoryFn={() => { }} optionalBool={true as true} />
73+
>Fail2 : Symbol(Fail2, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 19, 3))
74+
>Funk : Symbol(Funk, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 16, 3))
75+
>mandatoryFn : Symbol(mandatoryFn, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 19, 23))
76+
>optionalBool : Symbol(optionalBool, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 19, 47))
77+
78+
let True = true as true;
79+
>True : Symbol(True, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 20, 3))
80+
81+
let Fail3 = () => <Funk mandatoryFn={() => { }} optionalBool={True} />
82+
>Fail3 : Symbol(Fail3, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 21, 3))
83+
>Funk : Symbol(Funk, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 16, 3))
84+
>mandatoryFn : Symbol(mandatoryFn, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 21, 23))
85+
>optionalBool : Symbol(optionalBool, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 21, 47))
86+
>True : Symbol(True, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 20, 3))
87+
88+
let attrs2 = { optionalBool: true as true, mandatoryFn: () => { } }
89+
>attrs2 : Symbol(attrs2, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 22, 3))
90+
>optionalBool : Symbol(optionalBool, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 22, 14))
91+
>mandatoryFn : Symbol(mandatoryFn, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 22, 42))
92+
93+
let Success = () => <Funk {...attrs2} />
94+
>Success : Symbol(Success, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 23, 3))
95+
>Funk : Symbol(Funk, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 16, 3))
96+
>attrs2 : Symbol(attrs2, Decl(booleanLiteralsContextuallyTypedFromUnion.tsx, 22, 3))
97+

0 commit comments

Comments
 (0)