Limit the narrow-to-fresh rule added with boolean literals to only boolean literals (#27274)
* Remove the narrow-to-fresh rule added with boolean literals
* Revert "Remove the narrow-to-fresh rule added with boolean literals"
This reverts commit 9f96fe5da3
.
* Only apply freshness to booleans for now
* Add largeish example from issue
* Should be AND not OR
* Add minor improvements suggested by @ahejelsberg
* Reorder conditional a bit
This commit is contained in:
parent
b7fc092404
commit
e1c8dc2768
6 changed files with 576 additions and 4 deletions
|
@ -8873,7 +8873,7 @@ namespace ts {
|
|||
}
|
||||
switch (unionReduction) {
|
||||
case UnionReduction.Literal:
|
||||
if (includes & TypeFlags.StringOrNumberLiteralOrUnique) {
|
||||
if (includes & TypeFlags.StringOrNumberLiteralOrUnique | TypeFlags.BooleanLiteral) {
|
||||
removeRedundantLiteralTypes(typeSet, includes);
|
||||
}
|
||||
break;
|
||||
|
@ -12938,8 +12938,8 @@ namespace ts {
|
|||
function getDefinitelyFalsyPartOfType(type: Type): Type {
|
||||
return type.flags & TypeFlags.String ? emptyStringType :
|
||||
type.flags & TypeFlags.Number ? zeroType :
|
||||
type.flags & TypeFlags.Boolean || type === regularFalseType ? regularFalseType :
|
||||
type === falseType ? falseType :
|
||||
type === regularFalseType ||
|
||||
type === falseType ||
|
||||
type.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null) ||
|
||||
type.flags & TypeFlags.StringLiteral && (<LiteralType>type).value === "" ||
|
||||
type.flags & TypeFlags.NumberLiteral && (<LiteralType>type).value === 0 ? type :
|
||||
|
@ -14214,7 +14214,7 @@ namespace ts {
|
|||
return assignedType;
|
||||
}
|
||||
let reducedType = filterType(declaredType, t => typeMaybeAssignableTo(assignedType, t));
|
||||
if (assignedType.flags & (TypeFlags.FreshLiteral | TypeFlags.Literal)) {
|
||||
if (assignedType.flags & TypeFlags.FreshLiteral && assignedType.flags & TypeFlags.BooleanLiteral) {
|
||||
reducedType = mapType(reducedType, getFreshTypeOfLiteralType); // Ensure that if the assignment is a fresh type, that we narrow to fresh types
|
||||
}
|
||||
// Our crude heuristic produces an invalid result in some cases: see GH#26130.
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
tests/cases/compiler/literalFreshnessPropagationOnNarrowing.ts(37,5): error TS2322: Type '"y"' is not assignable to type '"x"'.
|
||||
tests/cases/compiler/literalFreshnessPropagationOnNarrowing.ts(60,5): error TS2322: Type 'string[]' is not assignable to type 'XY[]'.
|
||||
Type 'string' is not assignable to type 'XY'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/literalFreshnessPropagationOnNarrowing.ts (2 errors) ====
|
||||
function f1() {
|
||||
let b = true;
|
||||
let obj = { b };
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1 as-is: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
obj.b = false;
|
||||
}
|
||||
|
||||
function f2() {
|
||||
type Element = (string | false);
|
||||
type ElementOrArray = Element | Element[];
|
||||
let el: Element = null as any;
|
||||
let arr: Element[] = null as any;
|
||||
let elOrA: ElementOrArray = null as any;
|
||||
|
||||
// Desired/actual: All OK
|
||||
let a1: ElementOrArray = el;
|
||||
let a2: ElementOrArray = arr;
|
||||
let a3: ElementOrArray = [el];
|
||||
let a4: ElementOrArray = Array.isArray(elOrA) ? elOrA : [elOrA];
|
||||
|
||||
// Desired: OK
|
||||
// 3.0: Error
|
||||
// 3.1: OK
|
||||
let a5: ElementOrArray = [...Array.isArray(elOrA) ? elOrA : [elOrA]];
|
||||
}
|
||||
|
||||
function f3() {
|
||||
type XY = 'x' | 'y';
|
||||
const x: XY = 'x';
|
||||
let x2 = x;
|
||||
// Desired: OK (up for debate?)
|
||||
// 3.0: Error
|
||||
// 3.1 as-is: OK
|
||||
x2 = 'y';
|
||||
~~
|
||||
!!! error TS2322: Type '"y"' is not assignable to type '"x"'.
|
||||
|
||||
// Desired/actual: All OK
|
||||
let x3: XY = x;
|
||||
x3 = 'y';
|
||||
}
|
||||
|
||||
function f4() {
|
||||
const x: boolean = true;
|
||||
let x1 = x;
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
x1 = false;
|
||||
}
|
||||
|
||||
function f5() {
|
||||
type XY = 'x' | 'y';
|
||||
let arr: XY[] = ['x'];
|
||||
arr = ['y'];
|
||||
// Desired: OK
|
||||
// Error in all extant branches
|
||||
arr = [...['y']];
|
||||
~~~
|
||||
!!! error TS2322: Type 'string[]' is not assignable to type 'XY[]'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'XY'.
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
//// [literalFreshnessPropagationOnNarrowing.ts]
|
||||
function f1() {
|
||||
let b = true;
|
||||
let obj = { b };
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1 as-is: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
obj.b = false;
|
||||
}
|
||||
|
||||
function f2() {
|
||||
type Element = (string | false);
|
||||
type ElementOrArray = Element | Element[];
|
||||
let el: Element = null as any;
|
||||
let arr: Element[] = null as any;
|
||||
let elOrA: ElementOrArray = null as any;
|
||||
|
||||
// Desired/actual: All OK
|
||||
let a1: ElementOrArray = el;
|
||||
let a2: ElementOrArray = arr;
|
||||
let a3: ElementOrArray = [el];
|
||||
let a4: ElementOrArray = Array.isArray(elOrA) ? elOrA : [elOrA];
|
||||
|
||||
// Desired: OK
|
||||
// 3.0: Error
|
||||
// 3.1: OK
|
||||
let a5: ElementOrArray = [...Array.isArray(elOrA) ? elOrA : [elOrA]];
|
||||
}
|
||||
|
||||
function f3() {
|
||||
type XY = 'x' | 'y';
|
||||
const x: XY = 'x';
|
||||
let x2 = x;
|
||||
// Desired: OK (up for debate?)
|
||||
// 3.0: Error
|
||||
// 3.1 as-is: OK
|
||||
x2 = 'y';
|
||||
|
||||
// Desired/actual: All OK
|
||||
let x3: XY = x;
|
||||
x3 = 'y';
|
||||
}
|
||||
|
||||
function f4() {
|
||||
const x: boolean = true;
|
||||
let x1 = x;
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
x1 = false;
|
||||
}
|
||||
|
||||
function f5() {
|
||||
type XY = 'x' | 'y';
|
||||
let arr: XY[] = ['x'];
|
||||
arr = ['y'];
|
||||
// Desired: OK
|
||||
// Error in all extant branches
|
||||
arr = [...['y']];
|
||||
}
|
||||
|
||||
//// [literalFreshnessPropagationOnNarrowing.js]
|
||||
function f1() {
|
||||
var b = true;
|
||||
var obj = { b: b };
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1 as-is: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
obj.b = false;
|
||||
}
|
||||
function f2() {
|
||||
var el = null;
|
||||
var arr = null;
|
||||
var elOrA = null;
|
||||
// Desired/actual: All OK
|
||||
var a1 = el;
|
||||
var a2 = arr;
|
||||
var a3 = [el];
|
||||
var a4 = Array.isArray(elOrA) ? elOrA : [elOrA];
|
||||
// Desired: OK
|
||||
// 3.0: Error
|
||||
// 3.1: OK
|
||||
var a5 = (Array.isArray(elOrA) ? elOrA : [elOrA]).slice();
|
||||
}
|
||||
function f3() {
|
||||
var x = 'x';
|
||||
var x2 = x;
|
||||
// Desired: OK (up for debate?)
|
||||
// 3.0: Error
|
||||
// 3.1 as-is: OK
|
||||
x2 = 'y';
|
||||
// Desired/actual: All OK
|
||||
var x3 = x;
|
||||
x3 = 'y';
|
||||
}
|
||||
function f4() {
|
||||
var x = true;
|
||||
var x1 = x;
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
x1 = false;
|
||||
}
|
||||
function f5() {
|
||||
var arr = ['x'];
|
||||
arr = ['y'];
|
||||
// Desired: OK
|
||||
// Error in all extant branches
|
||||
arr = ['y'];
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
=== tests/cases/compiler/literalFreshnessPropagationOnNarrowing.ts ===
|
||||
function f1() {
|
||||
>f1 : Symbol(f1, Decl(literalFreshnessPropagationOnNarrowing.ts, 0, 0))
|
||||
|
||||
let b = true;
|
||||
>b : Symbol(b, Decl(literalFreshnessPropagationOnNarrowing.ts, 1, 7))
|
||||
|
||||
let obj = { b };
|
||||
>obj : Symbol(obj, Decl(literalFreshnessPropagationOnNarrowing.ts, 2, 7))
|
||||
>b : Symbol(b, Decl(literalFreshnessPropagationOnNarrowing.ts, 2, 15))
|
||||
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1 as-is: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
obj.b = false;
|
||||
>obj.b : Symbol(b, Decl(literalFreshnessPropagationOnNarrowing.ts, 2, 15))
|
||||
>obj : Symbol(obj, Decl(literalFreshnessPropagationOnNarrowing.ts, 2, 7))
|
||||
>b : Symbol(b, Decl(literalFreshnessPropagationOnNarrowing.ts, 2, 15))
|
||||
}
|
||||
|
||||
function f2() {
|
||||
>f2 : Symbol(f2, Decl(literalFreshnessPropagationOnNarrowing.ts, 8, 1))
|
||||
|
||||
type Element = (string | false);
|
||||
>Element : Symbol(Element, Decl(literalFreshnessPropagationOnNarrowing.ts, 10, 15))
|
||||
|
||||
type ElementOrArray = Element | Element[];
|
||||
>ElementOrArray : Symbol(ElementOrArray, Decl(literalFreshnessPropagationOnNarrowing.ts, 11, 36))
|
||||
>Element : Symbol(Element, Decl(literalFreshnessPropagationOnNarrowing.ts, 10, 15))
|
||||
>Element : Symbol(Element, Decl(literalFreshnessPropagationOnNarrowing.ts, 10, 15))
|
||||
|
||||
let el: Element = null as any;
|
||||
>el : Symbol(el, Decl(literalFreshnessPropagationOnNarrowing.ts, 13, 7))
|
||||
>Element : Symbol(Element, Decl(literalFreshnessPropagationOnNarrowing.ts, 10, 15))
|
||||
|
||||
let arr: Element[] = null as any;
|
||||
>arr : Symbol(arr, Decl(literalFreshnessPropagationOnNarrowing.ts, 14, 7))
|
||||
>Element : Symbol(Element, Decl(literalFreshnessPropagationOnNarrowing.ts, 10, 15))
|
||||
|
||||
let elOrA: ElementOrArray = null as any;
|
||||
>elOrA : Symbol(elOrA, Decl(literalFreshnessPropagationOnNarrowing.ts, 15, 7))
|
||||
>ElementOrArray : Symbol(ElementOrArray, Decl(literalFreshnessPropagationOnNarrowing.ts, 11, 36))
|
||||
|
||||
// Desired/actual: All OK
|
||||
let a1: ElementOrArray = el;
|
||||
>a1 : Symbol(a1, Decl(literalFreshnessPropagationOnNarrowing.ts, 18, 7))
|
||||
>ElementOrArray : Symbol(ElementOrArray, Decl(literalFreshnessPropagationOnNarrowing.ts, 11, 36))
|
||||
>el : Symbol(el, Decl(literalFreshnessPropagationOnNarrowing.ts, 13, 7))
|
||||
|
||||
let a2: ElementOrArray = arr;
|
||||
>a2 : Symbol(a2, Decl(literalFreshnessPropagationOnNarrowing.ts, 19, 7))
|
||||
>ElementOrArray : Symbol(ElementOrArray, Decl(literalFreshnessPropagationOnNarrowing.ts, 11, 36))
|
||||
>arr : Symbol(arr, Decl(literalFreshnessPropagationOnNarrowing.ts, 14, 7))
|
||||
|
||||
let a3: ElementOrArray = [el];
|
||||
>a3 : Symbol(a3, Decl(literalFreshnessPropagationOnNarrowing.ts, 20, 7))
|
||||
>ElementOrArray : Symbol(ElementOrArray, Decl(literalFreshnessPropagationOnNarrowing.ts, 11, 36))
|
||||
>el : Symbol(el, Decl(literalFreshnessPropagationOnNarrowing.ts, 13, 7))
|
||||
|
||||
let a4: ElementOrArray = Array.isArray(elOrA) ? elOrA : [elOrA];
|
||||
>a4 : Symbol(a4, Decl(literalFreshnessPropagationOnNarrowing.ts, 21, 7))
|
||||
>ElementOrArray : Symbol(ElementOrArray, Decl(literalFreshnessPropagationOnNarrowing.ts, 11, 36))
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>elOrA : Symbol(elOrA, Decl(literalFreshnessPropagationOnNarrowing.ts, 15, 7))
|
||||
>elOrA : Symbol(elOrA, Decl(literalFreshnessPropagationOnNarrowing.ts, 15, 7))
|
||||
>elOrA : Symbol(elOrA, Decl(literalFreshnessPropagationOnNarrowing.ts, 15, 7))
|
||||
|
||||
// Desired: OK
|
||||
// 3.0: Error
|
||||
// 3.1: OK
|
||||
let a5: ElementOrArray = [...Array.isArray(elOrA) ? elOrA : [elOrA]];
|
||||
>a5 : Symbol(a5, Decl(literalFreshnessPropagationOnNarrowing.ts, 26, 7))
|
||||
>ElementOrArray : Symbol(ElementOrArray, Decl(literalFreshnessPropagationOnNarrowing.ts, 11, 36))
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>elOrA : Symbol(elOrA, Decl(literalFreshnessPropagationOnNarrowing.ts, 15, 7))
|
||||
>elOrA : Symbol(elOrA, Decl(literalFreshnessPropagationOnNarrowing.ts, 15, 7))
|
||||
>elOrA : Symbol(elOrA, Decl(literalFreshnessPropagationOnNarrowing.ts, 15, 7))
|
||||
}
|
||||
|
||||
function f3() {
|
||||
>f3 : Symbol(f3, Decl(literalFreshnessPropagationOnNarrowing.ts, 27, 1))
|
||||
|
||||
type XY = 'x' | 'y';
|
||||
>XY : Symbol(XY, Decl(literalFreshnessPropagationOnNarrowing.ts, 29, 15))
|
||||
|
||||
const x: XY = 'x';
|
||||
>x : Symbol(x, Decl(literalFreshnessPropagationOnNarrowing.ts, 31, 9))
|
||||
>XY : Symbol(XY, Decl(literalFreshnessPropagationOnNarrowing.ts, 29, 15))
|
||||
|
||||
let x2 = x;
|
||||
>x2 : Symbol(x2, Decl(literalFreshnessPropagationOnNarrowing.ts, 32, 7))
|
||||
>x : Symbol(x, Decl(literalFreshnessPropagationOnNarrowing.ts, 31, 9))
|
||||
|
||||
// Desired: OK (up for debate?)
|
||||
// 3.0: Error
|
||||
// 3.1 as-is: OK
|
||||
x2 = 'y';
|
||||
>x2 : Symbol(x2, Decl(literalFreshnessPropagationOnNarrowing.ts, 32, 7))
|
||||
|
||||
// Desired/actual: All OK
|
||||
let x3: XY = x;
|
||||
>x3 : Symbol(x3, Decl(literalFreshnessPropagationOnNarrowing.ts, 39, 7))
|
||||
>XY : Symbol(XY, Decl(literalFreshnessPropagationOnNarrowing.ts, 29, 15))
|
||||
>x : Symbol(x, Decl(literalFreshnessPropagationOnNarrowing.ts, 31, 9))
|
||||
|
||||
x3 = 'y';
|
||||
>x3 : Symbol(x3, Decl(literalFreshnessPropagationOnNarrowing.ts, 39, 7))
|
||||
}
|
||||
|
||||
function f4() {
|
||||
>f4 : Symbol(f4, Decl(literalFreshnessPropagationOnNarrowing.ts, 41, 1))
|
||||
|
||||
const x: boolean = true;
|
||||
>x : Symbol(x, Decl(literalFreshnessPropagationOnNarrowing.ts, 44, 9))
|
||||
|
||||
let x1 = x;
|
||||
>x1 : Symbol(x1, Decl(literalFreshnessPropagationOnNarrowing.ts, 45, 7))
|
||||
>x : Symbol(x, Decl(literalFreshnessPropagationOnNarrowing.ts, 44, 9))
|
||||
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
x1 = false;
|
||||
>x1 : Symbol(x1, Decl(literalFreshnessPropagationOnNarrowing.ts, 45, 7))
|
||||
}
|
||||
|
||||
function f5() {
|
||||
>f5 : Symbol(f5, Decl(literalFreshnessPropagationOnNarrowing.ts, 51, 1))
|
||||
|
||||
type XY = 'x' | 'y';
|
||||
>XY : Symbol(XY, Decl(literalFreshnessPropagationOnNarrowing.ts, 53, 15))
|
||||
|
||||
let arr: XY[] = ['x'];
|
||||
>arr : Symbol(arr, Decl(literalFreshnessPropagationOnNarrowing.ts, 55, 7))
|
||||
>XY : Symbol(XY, Decl(literalFreshnessPropagationOnNarrowing.ts, 53, 15))
|
||||
|
||||
arr = ['y'];
|
||||
>arr : Symbol(arr, Decl(literalFreshnessPropagationOnNarrowing.ts, 55, 7))
|
||||
|
||||
// Desired: OK
|
||||
// Error in all extant branches
|
||||
arr = [...['y']];
|
||||
>arr : Symbol(arr, Decl(literalFreshnessPropagationOnNarrowing.ts, 55, 7))
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
=== tests/cases/compiler/literalFreshnessPropagationOnNarrowing.ts ===
|
||||
function f1() {
|
||||
>f1 : () => void
|
||||
|
||||
let b = true;
|
||||
>b : boolean
|
||||
>true : true
|
||||
|
||||
let obj = { b };
|
||||
>obj : { b: boolean; }
|
||||
>{ b } : { b: boolean; }
|
||||
>b : boolean
|
||||
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1 as-is: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
obj.b = false;
|
||||
>obj.b = false : false
|
||||
>obj.b : boolean
|
||||
>obj : { b: boolean; }
|
||||
>b : boolean
|
||||
>false : false
|
||||
}
|
||||
|
||||
function f2() {
|
||||
>f2 : () => void
|
||||
|
||||
type Element = (string | false);
|
||||
>Element : string | false
|
||||
>false : false
|
||||
|
||||
type ElementOrArray = Element | Element[];
|
||||
>ElementOrArray : string | false | (string | false)[]
|
||||
|
||||
let el: Element = null as any;
|
||||
>el : string | false
|
||||
>null as any : any
|
||||
>null : null
|
||||
|
||||
let arr: Element[] = null as any;
|
||||
>arr : (string | false)[]
|
||||
>null as any : any
|
||||
>null : null
|
||||
|
||||
let elOrA: ElementOrArray = null as any;
|
||||
>elOrA : string | false | (string | false)[]
|
||||
>null as any : any
|
||||
>null : null
|
||||
|
||||
// Desired/actual: All OK
|
||||
let a1: ElementOrArray = el;
|
||||
>a1 : string | false | (string | false)[]
|
||||
>el : string | false
|
||||
|
||||
let a2: ElementOrArray = arr;
|
||||
>a2 : string | false | (string | false)[]
|
||||
>arr : (string | false)[]
|
||||
|
||||
let a3: ElementOrArray = [el];
|
||||
>a3 : string | false | (string | false)[]
|
||||
>[el] : (string | false)[]
|
||||
>el : string | false
|
||||
|
||||
let a4: ElementOrArray = Array.isArray(elOrA) ? elOrA : [elOrA];
|
||||
>a4 : string | false | (string | false)[]
|
||||
>Array.isArray(elOrA) ? elOrA : [elOrA] : (string | false)[]
|
||||
>Array.isArray(elOrA) : boolean
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
>Array : ArrayConstructor
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
>elOrA : string | false | (string | false)[]
|
||||
>elOrA : (string | false)[]
|
||||
>[elOrA] : (string | false)[]
|
||||
>elOrA : string | false
|
||||
|
||||
// Desired: OK
|
||||
// 3.0: Error
|
||||
// 3.1: OK
|
||||
let a5: ElementOrArray = [...Array.isArray(elOrA) ? elOrA : [elOrA]];
|
||||
>a5 : string | false | (string | false)[]
|
||||
>[...Array.isArray(elOrA) ? elOrA : [elOrA]] : (string | false)[]
|
||||
>...Array.isArray(elOrA) ? elOrA : [elOrA] : string | false
|
||||
>Array.isArray(elOrA) ? elOrA : [elOrA] : (string | false)[]
|
||||
>Array.isArray(elOrA) : boolean
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
>Array : ArrayConstructor
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
>elOrA : string | false | (string | false)[]
|
||||
>elOrA : (string | false)[]
|
||||
>[elOrA] : (string | false)[]
|
||||
>elOrA : string | false
|
||||
}
|
||||
|
||||
function f3() {
|
||||
>f3 : () => void
|
||||
|
||||
type XY = 'x' | 'y';
|
||||
>XY : "x" | "y"
|
||||
|
||||
const x: XY = 'x';
|
||||
>x : "x" | "y"
|
||||
>'x' : "x"
|
||||
|
||||
let x2 = x;
|
||||
>x2 : "x"
|
||||
>x : "x"
|
||||
|
||||
// Desired: OK (up for debate?)
|
||||
// 3.0: Error
|
||||
// 3.1 as-is: OK
|
||||
x2 = 'y';
|
||||
>x2 = 'y' : "y"
|
||||
>x2 : "x"
|
||||
>'y' : "y"
|
||||
|
||||
// Desired/actual: All OK
|
||||
let x3: XY = x;
|
||||
>x3 : "x" | "y"
|
||||
>x : "x"
|
||||
|
||||
x3 = 'y';
|
||||
>x3 = 'y' : "y"
|
||||
>x3 : "x" | "y"
|
||||
>'y' : "y"
|
||||
}
|
||||
|
||||
function f4() {
|
||||
>f4 : () => void
|
||||
|
||||
const x: boolean = true;
|
||||
>x : boolean
|
||||
>true : true
|
||||
|
||||
let x1 = x;
|
||||
>x1 : boolean
|
||||
>x : true
|
||||
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
x1 = false;
|
||||
>x1 = false : false
|
||||
>x1 : boolean
|
||||
>false : false
|
||||
}
|
||||
|
||||
function f5() {
|
||||
>f5 : () => void
|
||||
|
||||
type XY = 'x' | 'y';
|
||||
>XY : "x" | "y"
|
||||
|
||||
let arr: XY[] = ['x'];
|
||||
>arr : ("x" | "y")[]
|
||||
>['x'] : "x"[]
|
||||
>'x' : "x"
|
||||
|
||||
arr = ['y'];
|
||||
>arr = ['y'] : "y"[]
|
||||
>arr : ("x" | "y")[]
|
||||
>['y'] : "y"[]
|
||||
>'y' : "y"
|
||||
|
||||
// Desired: OK
|
||||
// Error in all extant branches
|
||||
arr = [...['y']];
|
||||
>arr = [...['y']] : string[]
|
||||
>arr : ("x" | "y")[]
|
||||
>[...['y']] : string[]
|
||||
>...['y'] : string
|
||||
>['y'] : string[]
|
||||
>'y' : "y"
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
function f1() {
|
||||
let b = true;
|
||||
let obj = { b };
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1 as-is: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
obj.b = false;
|
||||
}
|
||||
|
||||
function f2() {
|
||||
type Element = (string | false);
|
||||
type ElementOrArray = Element | Element[];
|
||||
let el: Element = null as any;
|
||||
let arr: Element[] = null as any;
|
||||
let elOrA: ElementOrArray = null as any;
|
||||
|
||||
// Desired/actual: All OK
|
||||
let a1: ElementOrArray = el;
|
||||
let a2: ElementOrArray = arr;
|
||||
let a3: ElementOrArray = [el];
|
||||
let a4: ElementOrArray = Array.isArray(elOrA) ? elOrA : [elOrA];
|
||||
|
||||
// Desired: OK
|
||||
// 3.0: Error
|
||||
// 3.1: OK
|
||||
let a5: ElementOrArray = [...Array.isArray(elOrA) ? elOrA : [elOrA]];
|
||||
}
|
||||
|
||||
function f3() {
|
||||
type XY = 'x' | 'y';
|
||||
const x: XY = 'x';
|
||||
let x2 = x;
|
||||
// Desired: OK (up for debate?)
|
||||
// 3.0: Error
|
||||
// 3.1 as-is: OK
|
||||
x2 = 'y';
|
||||
|
||||
// Desired/actual: All OK
|
||||
let x3: XY = x;
|
||||
x3 = 'y';
|
||||
}
|
||||
|
||||
function f4() {
|
||||
const x: boolean = true;
|
||||
let x1 = x;
|
||||
// Desired: OK
|
||||
// 3.0: OK
|
||||
// 3.1: OK
|
||||
// 3.1 minus widening propagation: error
|
||||
x1 = false;
|
||||
}
|
||||
|
||||
function f5() {
|
||||
type XY = 'x' | 'y';
|
||||
let arr: XY[] = ['x'];
|
||||
arr = ['y'];
|
||||
// Desired: OK
|
||||
// Error in all extant branches
|
||||
arr = [...['y']];
|
||||
}
|
Loading…
Reference in a new issue