diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c6df5749e4a..78fd663bbb9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18104,7 +18104,8 @@ namespace ts { return true; } } - else { + else if (!((source.flags | target.flags) & (TypeFlags.UnionOrIntersection | TypeFlags.IndexedAccess | TypeFlags.Conditional | TypeFlags.Substitution))) { + // We have excluded types that may simplify to other forms, so types must have identical flags if (source.flags !== target.flags) return false; if (source.flags & TypeFlags.Singleton) return true; } diff --git a/tests/baselines/reference/identityRelationNeverTypes.js b/tests/baselines/reference/identityRelationNeverTypes.js new file mode 100644 index 00000000000..efe85defc1b --- /dev/null +++ b/tests/baselines/reference/identityRelationNeverTypes.js @@ -0,0 +1,42 @@ +//// [identityRelationNeverTypes.ts] +// Repro from #47996 + +type Equals = (() => T extends B ? 1 : 0) extends (() => T extends A ? 1 : 0) ? true : false; + +declare class State { + _context: TContext; + _value: string; + matches(stateValue: TSV): this is State & { value: TSV }; +} + +function f1(state: State<{ foo: number }>) { + if (state.matches('a') && state.matches('a.b')) { + state; // never + type T1 = Equals; // true + type T2 = Equals; // true + } +} + + +//// [identityRelationNeverTypes.js] +"use strict"; +// Repro from #47996 +function f1(state) { + if (state.matches('a') && state.matches('a.b')) { + state; // never + } +} + + +//// [identityRelationNeverTypes.d.ts] +declare type Equals = (() => T extends B ? 1 : 0) extends (() => T extends A ? 1 : 0) ? true : false; +declare class State { + _context: TContext; + _value: string; + matches(stateValue: TSV): this is State & { + value: TSV; + }; +} +declare function f1(state: State<{ + foo: number; +}>): void; diff --git a/tests/baselines/reference/identityRelationNeverTypes.symbols b/tests/baselines/reference/identityRelationNeverTypes.symbols new file mode 100644 index 00000000000..0bc98f71dca --- /dev/null +++ b/tests/baselines/reference/identityRelationNeverTypes.symbols @@ -0,0 +1,64 @@ +=== tests/cases/compiler/identityRelationNeverTypes.ts === +// Repro from #47996 + +type Equals = (() => T extends B ? 1 : 0) extends (() => T extends A ? 1 : 0) ? true : false; +>Equals : Symbol(Equals, Decl(identityRelationNeverTypes.ts, 0, 0)) +>A : Symbol(A, Decl(identityRelationNeverTypes.ts, 2, 12)) +>B : Symbol(B, Decl(identityRelationNeverTypes.ts, 2, 14)) +>T : Symbol(T, Decl(identityRelationNeverTypes.ts, 2, 22)) +>T : Symbol(T, Decl(identityRelationNeverTypes.ts, 2, 22)) +>B : Symbol(B, Decl(identityRelationNeverTypes.ts, 2, 14)) +>T : Symbol(T, Decl(identityRelationNeverTypes.ts, 2, 61)) +>T : Symbol(T, Decl(identityRelationNeverTypes.ts, 2, 61)) +>A : Symbol(A, Decl(identityRelationNeverTypes.ts, 2, 12)) + +declare class State { +>State : Symbol(State, Decl(identityRelationNeverTypes.ts, 2, 105)) +>TContext : Symbol(TContext, Decl(identityRelationNeverTypes.ts, 4, 20)) + + _context: TContext; +>_context : Symbol(State._context, Decl(identityRelationNeverTypes.ts, 4, 31)) +>TContext : Symbol(TContext, Decl(identityRelationNeverTypes.ts, 4, 20)) + + _value: string; +>_value : Symbol(State._value, Decl(identityRelationNeverTypes.ts, 5, 23)) + + matches(stateValue: TSV): this is State & { value: TSV }; +>matches : Symbol(State.matches, Decl(identityRelationNeverTypes.ts, 6, 19)) +>TSV : Symbol(TSV, Decl(identityRelationNeverTypes.ts, 7, 12)) +>stateValue : Symbol(stateValue, Decl(identityRelationNeverTypes.ts, 7, 32)) +>TSV : Symbol(TSV, Decl(identityRelationNeverTypes.ts, 7, 12)) +>State : Symbol(State, Decl(identityRelationNeverTypes.ts, 2, 105)) +>TContext : Symbol(TContext, Decl(identityRelationNeverTypes.ts, 4, 20)) +>value : Symbol(value, Decl(identityRelationNeverTypes.ts, 7, 77)) +>TSV : Symbol(TSV, Decl(identityRelationNeverTypes.ts, 7, 12)) +} + +function f1(state: State<{ foo: number }>) { +>f1 : Symbol(f1, Decl(identityRelationNeverTypes.ts, 8, 1)) +>state : Symbol(state, Decl(identityRelationNeverTypes.ts, 10, 12)) +>State : Symbol(State, Decl(identityRelationNeverTypes.ts, 2, 105)) +>foo : Symbol(foo, Decl(identityRelationNeverTypes.ts, 10, 26)) + + if (state.matches('a') && state.matches('a.b')) { +>state.matches : Symbol(State.matches, Decl(identityRelationNeverTypes.ts, 6, 19)) +>state : Symbol(state, Decl(identityRelationNeverTypes.ts, 10, 12)) +>matches : Symbol(State.matches, Decl(identityRelationNeverTypes.ts, 6, 19)) +>state.matches : Symbol(State.matches, Decl(identityRelationNeverTypes.ts, 6, 19)) +>state : Symbol(state, Decl(identityRelationNeverTypes.ts, 10, 12)) +>matches : Symbol(State.matches, Decl(identityRelationNeverTypes.ts, 6, 19)) + + state; // never +>state : Symbol(state, Decl(identityRelationNeverTypes.ts, 10, 12)) + + type T1 = Equals; // true +>T1 : Symbol(T1, Decl(identityRelationNeverTypes.ts, 12, 14)) +>Equals : Symbol(Equals, Decl(identityRelationNeverTypes.ts, 0, 0)) +>state : Symbol(state, Decl(identityRelationNeverTypes.ts, 10, 12)) + + type T2 = Equals; // true +>T2 : Symbol(T2, Decl(identityRelationNeverTypes.ts, 13, 46)) +>Equals : Symbol(Equals, Decl(identityRelationNeverTypes.ts, 0, 0)) + } +} + diff --git a/tests/baselines/reference/identityRelationNeverTypes.types b/tests/baselines/reference/identityRelationNeverTypes.types new file mode 100644 index 00000000000..d94a3794c78 --- /dev/null +++ b/tests/baselines/reference/identityRelationNeverTypes.types @@ -0,0 +1,53 @@ +=== tests/cases/compiler/identityRelationNeverTypes.ts === +// Repro from #47996 + +type Equals = (() => T extends B ? 1 : 0) extends (() => T extends A ? 1 : 0) ? true : false; +>Equals : Equals +>true : true +>false : false + +declare class State { +>State : State + + _context: TContext; +>_context : TContext + + _value: string; +>_value : string + + matches(stateValue: TSV): this is State & { value: TSV }; +>matches : (stateValue: TSV) => this is State & { value: TSV; } +>stateValue : TSV +>value : TSV +} + +function f1(state: State<{ foo: number }>) { +>f1 : (state: State<{ foo: number;}>) => void +>state : State<{ foo: number; }> +>foo : number + + if (state.matches('a') && state.matches('a.b')) { +>state.matches('a') && state.matches('a.b') : boolean +>state.matches('a') : boolean +>state.matches : (stateValue: TSV) => this is State<{ foo: number; }> & { value: TSV; } +>state : State<{ foo: number; }> +>matches : (stateValue: TSV) => this is State<{ foo: number; }> & { value: TSV; } +>'a' : "a" +>state.matches('a.b') : boolean +>state.matches : (stateValue: TSV) => this is State<{ foo: number; }> & { value: TSV; } +>state : State<{ foo: number; }> & { value: "a"; } +>matches : (stateValue: TSV) => this is State<{ foo: number; }> & { value: TSV; } +>'a.b' : "a.b" + + state; // never +>state : never + + type T1 = Equals; // true +>T1 : true +>state : never + + type T2 = Equals; // true +>T2 : true + } +} + diff --git a/tests/cases/compiler/identityRelationNeverTypes.ts b/tests/cases/compiler/identityRelationNeverTypes.ts new file mode 100644 index 00000000000..62d233bcf06 --- /dev/null +++ b/tests/cases/compiler/identityRelationNeverTypes.ts @@ -0,0 +1,20 @@ +// @strict: true +// @declaration: true + +// Repro from #47996 + +type Equals = (() => T extends B ? 1 : 0) extends (() => T extends A ? 1 : 0) ? true : false; + +declare class State { + _context: TContext; + _value: string; + matches(stateValue: TSV): this is State & { value: TSV }; +} + +function f1(state: State<{ foo: number }>) { + if (state.matches('a') && state.matches('a.b')) { + state; // never + type T1 = Equals; // true + type T2 = Equals; // true + } +}