Filter origin types when filtering union types (#42378)

* When filtering a union type, also filter its origin type, if any

* Accept new baselines
This commit is contained in:
Anders Hejlsberg 2021-01-20 06:37:02 -10:00 committed by GitHub
parent 1cef53f9f5
commit 028f14c507
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 30 additions and 10 deletions

View File

@ -21689,7 +21689,27 @@ namespace ts {
if (type.flags & TypeFlags.Union) {
const types = (<UnionType>type).types;
const filtered = filter(types, f);
return filtered === types ? type : getUnionTypeFromSortedList(filtered, (<UnionType>type).objectFlags);
if (filtered === types) {
return type;
}
const origin = (<UnionType>type).origin;
let newOrigin: Type | undefined;
if (origin && origin.flags & TypeFlags.Union) {
// If the origin type is a (denormalized) union type, filter its non-union constituents. If that ends
// up removing a smaller number of types than in the normalized constituent set (meaning some of the
// filtered types are within nested unions in the origin), then we can't construct a new origin type.
// Otherwise, if we have exactly one type left in the origin set, return that as the filtered type.
// Otherwise, construct a new filtered origin type.
const originTypes = (<UnionType>origin).types;
const originFiltered = filter(originTypes, t => !!(t.flags & TypeFlags.Union) || f(t));
if (originTypes.length - originFiltered.length === types.length - filtered.length) {
if (originFiltered.length === 1) {
return originFiltered[0];
}
newOrigin = createOriginUnionOrIntersectionType(TypeFlags.Union, originFiltered);
}
}
return getUnionTypeFromSortedList(filtered, (<UnionType>type).objectFlags, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, newOrigin);
}
return type.flags & TypeFlags.Never || f(type) ? type : neverType;
}

View File

@ -1,5 +1,5 @@
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(7,9): error TS7027: Unreachable code detected.
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(235,5): error TS2367: This condition will always return 'false' since the types '"a" | "b"' and '"c"' have no overlap.
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(235,5): error TS2367: This condition will always return 'false' since the types 'keyof O' and '"c"' have no overlap.
==== tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts (2 errors) ====
@ -241,7 +241,7 @@ tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(235,5): error
}
k === 'c'; // Error
~~~~~~~~~
!!! error TS2367: This condition will always return 'false' since the types '"a" | "b"' and '"c"' have no overlap.
!!! error TS2367: This condition will always return 'false' since the types 'keyof O' and '"c"' have no overlap.
return o[k];
}

View File

@ -695,12 +695,12 @@ function ff(o: O, k: K) {
}
k === 'c'; // Error
>k === 'c' : boolean
>k : "a" | "b"
>k : keyof O
>'c' : "c"
return o[k];
>o[k] : number
>o : O
>k : "a" | "b"
>k : keyof O
}

View File

@ -52,6 +52,6 @@ function asObservable(input: string | ObservableInput<string>): Observable<strin
>input : string
>from(input) : Observable<string>
>from : <O extends ObservableInput<any>>(input: O) => Observable<ObservedValueOf<O>>
>input : Subscribable<never> | Subscribable<string>
>input : ObservableInput<string>
}

View File

@ -95,7 +95,7 @@ function fail(s: Shapes) {
if (s.kind === "circle") {
>s.kind === "circle" : boolean
>s.kind : "square" | "circle"
>s : Square | Circle
>s : Shape
>kind : "square" | "circle"
>"circle" : "circle"

View File

@ -27,6 +27,6 @@ foo1 = [...Array.isArray(foo2) ? foo2 : [foo2]];
>isArray : (arg: any) => arg is any[]
>foo2 : Foo
>foo2 : FooArray
>[foo2] : (string | false)[]
>foo2 : string | false
>[foo2] : FooBase[]
>foo2 : FooBase

View File

@ -29,7 +29,7 @@ function f(foo: T) {
>foo : T
return foo;
>foo : "a" | "b"
>foo : S
}
else {
return foo[0];