mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Improve detection of cases where subtype reduction is unnecessary (#53435)
This commit is contained in:
parent
37bafa539c
commit
511921e1e2
@ -25891,7 +25891,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function isTypeSubsetOf(source: Type, target: Type) {
|
||||
return source === target || target.flags & TypeFlags.Union && isTypeSubsetOfUnion(source, target as UnionType);
|
||||
return !!(source === target || source.flags & TypeFlags.Never || target.flags & TypeFlags.Union && isTypeSubsetOfUnion(source, target as UnionType));
|
||||
}
|
||||
|
||||
function isTypeSubsetOfUnion(source: Type, target: UnionType) {
|
||||
@ -26715,7 +26715,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// If an antecedent type is not a subset of the declared type, we need to perform
|
||||
// subtype reduction. This happens when a "foreign" type is injected into the control
|
||||
// flow using the instanceof operator or a user defined type predicate.
|
||||
if (!isTypeSubsetOf(type, declaredType)) {
|
||||
if (!isTypeSubsetOf(type, initialType)) {
|
||||
subtypeReduction = true;
|
||||
}
|
||||
if (isIncomplete(flowType)) {
|
||||
@ -26733,7 +26733,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return type;
|
||||
}
|
||||
antecedentTypes.push(type);
|
||||
if (!isTypeSubsetOf(type, declaredType)) {
|
||||
if (!isTypeSubsetOf(type, initialType)) {
|
||||
subtypeReduction = true;
|
||||
}
|
||||
if (isIncomplete(flowType)) {
|
||||
@ -26808,7 +26808,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// If an antecedent type is not a subset of the declared type, we need to perform
|
||||
// subtype reduction. This happens when a "foreign" type is injected into the control
|
||||
// flow using the instanceof operator or a user defined type predicate.
|
||||
if (!isTypeSubsetOf(type, declaredType)) {
|
||||
if (!isTypeSubsetOf(type, initialType)) {
|
||||
subtypeReduction = true;
|
||||
}
|
||||
// If the type at a particular antecedent path is the declared type there is no
|
||||
|
||||
51
tests/baselines/reference/noSubtypeReduction.symbols
Normal file
51
tests/baselines/reference/noSubtypeReduction.symbols
Normal file
@ -0,0 +1,51 @@
|
||||
=== tests/cases/compiler/noSubtypeReduction.ts ===
|
||||
// Repro from #53425
|
||||
|
||||
export interface IA {
|
||||
>IA : Symbol(IA, Decl(noSubtypeReduction.ts, 0, 0))
|
||||
|
||||
arr: { A: number; }[];
|
||||
>arr : Symbol(IA.arr, Decl(noSubtypeReduction.ts, 2, 21))
|
||||
>A : Symbol(A, Decl(noSubtypeReduction.ts, 3, 10))
|
||||
}
|
||||
|
||||
export interface IAB {
|
||||
>IAB : Symbol(IAB, Decl(noSubtypeReduction.ts, 4, 1))
|
||||
|
||||
arr: { A: number; B: number; }[];
|
||||
>arr : Symbol(IAB.arr, Decl(noSubtypeReduction.ts, 6, 22))
|
||||
>A : Symbol(A, Decl(noSubtypeReduction.ts, 7, 10))
|
||||
>B : Symbol(B, Decl(noSubtypeReduction.ts, 7, 21))
|
||||
}
|
||||
|
||||
export function F(x: IA | IAB) {
|
||||
>F : Symbol(F, Decl(noSubtypeReduction.ts, 8, 1))
|
||||
>x : Symbol(x, Decl(noSubtypeReduction.ts, 10, 18))
|
||||
>IA : Symbol(IA, Decl(noSubtypeReduction.ts, 0, 0))
|
||||
>IAB : Symbol(IAB, Decl(noSubtypeReduction.ts, 4, 1))
|
||||
|
||||
const useB = (t: number) => { };
|
||||
>useB : Symbol(useB, Decl(noSubtypeReduction.ts, 11, 9))
|
||||
>t : Symbol(t, Decl(noSubtypeReduction.ts, 11, 18))
|
||||
|
||||
for (const el of x.arr) {
|
||||
>el : Symbol(el, Decl(noSubtypeReduction.ts, 12, 14))
|
||||
>x.arr : Symbol(arr, Decl(noSubtypeReduction.ts, 2, 21), Decl(noSubtypeReduction.ts, 6, 22))
|
||||
>x : Symbol(x, Decl(noSubtypeReduction.ts, 10, 18))
|
||||
>arr : Symbol(arr, Decl(noSubtypeReduction.ts, 2, 21), Decl(noSubtypeReduction.ts, 6, 22))
|
||||
|
||||
if ('A' in el) { }
|
||||
>el : Symbol(el, Decl(noSubtypeReduction.ts, 12, 14))
|
||||
|
||||
if ('B' in el) {
|
||||
>el : Symbol(el, Decl(noSubtypeReduction.ts, 12, 14))
|
||||
|
||||
useB(el.B);
|
||||
>useB : Symbol(useB, Decl(noSubtypeReduction.ts, 11, 9))
|
||||
>el.B : Symbol(B, Decl(noSubtypeReduction.ts, 7, 21))
|
||||
>el : Symbol(el, Decl(noSubtypeReduction.ts, 12, 14))
|
||||
>B : Symbol(B, Decl(noSubtypeReduction.ts, 7, 21))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
51
tests/baselines/reference/noSubtypeReduction.types
Normal file
51
tests/baselines/reference/noSubtypeReduction.types
Normal file
@ -0,0 +1,51 @@
|
||||
=== tests/cases/compiler/noSubtypeReduction.ts ===
|
||||
// Repro from #53425
|
||||
|
||||
export interface IA {
|
||||
arr: { A: number; }[];
|
||||
>arr : { A: number; }[]
|
||||
>A : number
|
||||
}
|
||||
|
||||
export interface IAB {
|
||||
arr: { A: number; B: number; }[];
|
||||
>arr : { A: number; B: number; }[]
|
||||
>A : number
|
||||
>B : number
|
||||
}
|
||||
|
||||
export function F(x: IA | IAB) {
|
||||
>F : (x: IA | IAB) => void
|
||||
>x : IA | IAB
|
||||
|
||||
const useB = (t: number) => { };
|
||||
>useB : (t: number) => void
|
||||
>(t: number) => { } : (t: number) => void
|
||||
>t : number
|
||||
|
||||
for (const el of x.arr) {
|
||||
>el : { A: number; } | { A: number; B: number; }
|
||||
>x.arr : { A: number; }[] | { A: number; B: number; }[]
|
||||
>x : IA | IAB
|
||||
>arr : { A: number; }[] | { A: number; B: number; }[]
|
||||
|
||||
if ('A' in el) { }
|
||||
>'A' in el : boolean
|
||||
>'A' : "A"
|
||||
>el : { A: number; } | { A: number; B: number; }
|
||||
|
||||
if ('B' in el) {
|
||||
>'B' in el : boolean
|
||||
>'B' : "B"
|
||||
>el : { A: number; } | { A: number; B: number; }
|
||||
|
||||
useB(el.B);
|
||||
>useB(el.B) : void
|
||||
>useB : (t: number) => void
|
||||
>el.B : number
|
||||
>el : { A: number; B: number; }
|
||||
>B : number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
22
tests/cases/compiler/noSubtypeReduction.ts
Normal file
22
tests/cases/compiler/noSubtypeReduction.ts
Normal file
@ -0,0 +1,22 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
// Repro from #53425
|
||||
|
||||
export interface IA {
|
||||
arr: { A: number; }[];
|
||||
}
|
||||
|
||||
export interface IAB {
|
||||
arr: { A: number; B: number; }[];
|
||||
}
|
||||
|
||||
export function F(x: IA | IAB) {
|
||||
const useB = (t: number) => { };
|
||||
for (const el of x.arr) {
|
||||
if ('A' in el) { }
|
||||
if ('B' in el) {
|
||||
useB(el.B);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user