mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-12 03:20:56 -06:00
Improve reduction of similar intersections in type inference (#51405)
* Change criteria for reducing intersections in type inference * Add regression test
This commit is contained in:
parent
f1d62f4dc4
commit
f0216e3421
@ -22728,14 +22728,11 @@ namespace ts {
|
||||
}
|
||||
source = getUnionType(sources);
|
||||
}
|
||||
else if (target.flags & TypeFlags.Intersection && some((target as IntersectionType).types,
|
||||
t => !!getInferenceInfoForType(t) || (isGenericMappedType(t) && !!getInferenceInfoForType(getHomomorphicTypeVariable(t) || neverType)))) {
|
||||
// We reduce intersection types only when they contain naked type parameters. For example, when
|
||||
// inferring from 'string[] & { extra: any }' to 'string[] & T' we want to remove string[] and
|
||||
else if (target.flags & TypeFlags.Intersection && !every((target as IntersectionType).types, isNonGenericObjectType)) {
|
||||
// We reduce intersection types unless they're simple combinations of object types. For example,
|
||||
// when inferring from 'string[] & { extra: any }' to 'string[] & T' we want to remove string[] and
|
||||
// infer { extra: any } for T. But when inferring to 'string[] & Iterable<T>' we want to keep the
|
||||
// string[] on the source side and infer string for T.
|
||||
// Likewise, we consider a homomorphic mapped type constrainted to the target type parameter as similar to a "naked type variable"
|
||||
// in such scenarios.
|
||||
if (!(source.flags & TypeFlags.Union)) {
|
||||
// Infer between identically matching source and target constituents and remove the matching types.
|
||||
const [sources, targets] = inferFromMatchingTypes(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], (target as IntersectionType).types, isTypeIdenticalTo);
|
||||
|
||||
@ -86,6 +86,12 @@ declare function foo<T, U>(obj: T & AB<U>): [T, U];
|
||||
declare let ab: AB<string>;
|
||||
|
||||
let z = foo(ab); // [AB<string>, string]
|
||||
|
||||
// Repro from #51399
|
||||
|
||||
declare let a: <T>() => (T extends true ? true : false) & boolean;
|
||||
declare let b: <T>() => (T extends true ? true : false) & boolean;
|
||||
a = b;
|
||||
|
||||
|
||||
//// [unionAndIntersectionInference3.js]
|
||||
@ -105,4 +111,5 @@ let x2 = foo2(sa); // unknown
|
||||
let y2 = foo2(sx); // { extra: number }
|
||||
withRouter(MyComponent);
|
||||
let z = foo(ab); // [AB<string>, string]
|
||||
a = b;
|
||||
export {};
|
||||
|
||||
@ -309,3 +309,19 @@ let z = foo(ab); // [AB<string>, string]
|
||||
>foo : Symbol(foo, Decl(unionAndIntersectionInference3.ts, 80, 33))
|
||||
>ab : Symbol(ab, Decl(unionAndIntersectionInference3.ts, 84, 11))
|
||||
|
||||
// Repro from #51399
|
||||
|
||||
declare let a: <T>() => (T extends true ? true : false) & boolean;
|
||||
>a : Symbol(a, Decl(unionAndIntersectionInference3.ts, 90, 11))
|
||||
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 90, 16))
|
||||
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 90, 16))
|
||||
|
||||
declare let b: <T>() => (T extends true ? true : false) & boolean;
|
||||
>b : Symbol(b, Decl(unionAndIntersectionInference3.ts, 91, 11))
|
||||
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 91, 16))
|
||||
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 91, 16))
|
||||
|
||||
a = b;
|
||||
>a : Symbol(a, Decl(unionAndIntersectionInference3.ts, 90, 11))
|
||||
>b : Symbol(b, Decl(unionAndIntersectionInference3.ts, 91, 11))
|
||||
|
||||
|
||||
@ -199,3 +199,22 @@ let z = foo(ab); // [AB<string>, string]
|
||||
>foo : <T, U>(obj: T & AB<U>) => [T, U]
|
||||
>ab : AB<string>
|
||||
|
||||
// Repro from #51399
|
||||
|
||||
declare let a: <T>() => (T extends true ? true : false) & boolean;
|
||||
>a : <T>() => (T extends true ? true : false) & boolean
|
||||
>true : true
|
||||
>true : true
|
||||
>false : false
|
||||
|
||||
declare let b: <T>() => (T extends true ? true : false) & boolean;
|
||||
>b : <T>() => (T extends true ? true : false) & boolean
|
||||
>true : true
|
||||
>true : true
|
||||
>false : false
|
||||
|
||||
a = b;
|
||||
>a = b : <T>() => (T extends true ? true : false) & boolean
|
||||
>a : <T>() => (T extends true ? true : false) & boolean
|
||||
>b : <T>() => (T extends true ? true : false) & boolean
|
||||
|
||||
|
||||
@ -88,3 +88,9 @@ declare function foo<T, U>(obj: T & AB<U>): [T, U];
|
||||
declare let ab: AB<string>;
|
||||
|
||||
let z = foo(ab); // [AB<string>, string]
|
||||
|
||||
// Repro from #51399
|
||||
|
||||
declare let a: <T>() => (T extends true ? true : false) & boolean;
|
||||
declare let b: <T>() => (T extends true ? true : false) & boolean;
|
||||
a = b;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user