diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8305443a19bac..982a66ef58720 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12519,7 +12519,7 @@ namespace ts { source = getSimplifiedType(source, /*writing*/ false); } if (target.flags & TypeFlags.Simplifiable) { - target = getSimplifiedType(target, /*writing*/ true); + target = getSimplifiedType(target, (source.flags & TypeFlags.IndexedAccess) !== 0 && (target.flags & TypeFlags.IndexedAccess) !== 0); } // Try to see if we're relating something like `Foo` -> `Bar | null | undefined`. diff --git a/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt b/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt index af63c18523d6a..ceee293b747d9 100644 --- a/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt +++ b/tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt @@ -1,24 +1,21 @@ tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts(33,5): error TS2322: Type '{ type: T; localChannelId: string; }' is not assignable to type 'NewChannel | ChannelOfType>'. Type '{ type: T; localChannelId: string; }' is not assignable to type 'Pick | ChannelOfType, "type">'. Types of property 'type' are incompatible. - Type 'T' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. - Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. - Type '"text"' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. - Type '"text"' is not assignable to type 'ChannelOfType["type"]'. - Type 'T' is not assignable to type 'ChannelOfType["type"]'. - Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"]'. - Type '"text"' is not assignable to type 'ChannelOfType["type"]'. - Type '"text"' is not assignable to type 'T & "text"'. - Type '"text"' is not assignable to type 'T'. - '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. - Type 'T' is not assignable to type 'T & "text"'. - Type '"text" | "email"' is not assignable to type 'T & "text"'. - Type '"text"' is not assignable to type 'T & "text"'. - Type '"text"' is not assignable to type 'T'. - '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. - Type 'T' is not assignable to type '"text"'. - Type '"text" | "email"' is not assignable to type '"text"'. - Type '"email"' is not assignable to type '"text"'. + Type 'T' is not assignable to type 'ChannelOfType["type"] | ChannelOfType["type"]'. + Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"] | ChannelOfType["type"]'. + Type '"text"' is not assignable to type 'ChannelOfType["type"] | ChannelOfType["type"]'. + Type 'T' is not assignable to type 'ChannelOfType["type"]'. + Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"]'. + Type '"text"' is not assignable to type 'ChannelOfType["type"]'. + Type '"text"' is not assignable to type 'T & "email"'. + Type '"text"' is not assignable to type 'T'. + '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. + Type 'T' is not assignable to type 'T & "email"'. + Type '"text" | "email"' is not assignable to type 'T & "email"'. + Type '"text"' is not assignable to type 'T & "email"'. + Type '"text"' is not assignable to type 'T'. + '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. + Type 'T' is not assignable to type '"email"'. ==== tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts (1 errors) ==== @@ -59,24 +56,21 @@ tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.t !!! error TS2322: Type '{ type: T; localChannelId: string; }' is not assignable to type 'NewChannel | ChannelOfType>'. !!! error TS2322: Type '{ type: T; localChannelId: string; }' is not assignable to type 'Pick | ChannelOfType, "type">'. !!! error TS2322: Types of property 'type' are incompatible. -!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. -!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. -!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType["type"] & ChannelOfType["type"]'. -!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType["type"]'. -!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType["type"]'. -!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"]'. -!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType["type"]'. -!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'. -!!! error TS2322: Type '"text"' is not assignable to type 'T'. -!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. -!!! error TS2322: Type 'T' is not assignable to type 'T & "text"'. -!!! error TS2322: Type '"text" | "email"' is not assignable to type 'T & "text"'. -!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'. -!!! error TS2322: Type '"text"' is not assignable to type 'T'. -!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. -!!! error TS2322: Type 'T' is not assignable to type '"text"'. -!!! error TS2322: Type '"text" | "email"' is not assignable to type '"text"'. -!!! error TS2322: Type '"email"' is not assignable to type '"text"'. +!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType["type"] | ChannelOfType["type"]'. +!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"] | ChannelOfType["type"]'. +!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType["type"] | ChannelOfType["type"]'. +!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType["type"]'. +!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType["type"]'. +!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType["type"]'. +!!! error TS2322: Type '"text"' is not assignable to type 'T & "email"'. +!!! error TS2322: Type '"text"' is not assignable to type 'T'. +!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. +!!! error TS2322: Type 'T' is not assignable to type 'T & "email"'. +!!! error TS2322: Type '"text" | "email"' is not assignable to type 'T & "email"'. +!!! error TS2322: Type '"text"' is not assignable to type 'T & "email"'. +!!! error TS2322: Type '"text"' is not assignable to type 'T'. +!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'. +!!! error TS2322: Type 'T' is not assignable to type '"email"'. } const newTextChannel = makeNewChannel('text'); diff --git a/tests/baselines/reference/indexedAccessRelation.errors.txt b/tests/baselines/reference/indexedAccessRelation.errors.txt index 84e65df856d28..fe2843a662e51 100644 --- a/tests/baselines/reference/indexedAccessRelation.errors.txt +++ b/tests/baselines/reference/indexedAccessRelation.errors.txt @@ -34,4 +34,30 @@ tests/cases/compiler/indexedAccessRelation.ts(16,23): error TS2345: Argument of !!! error TS2345: Type 'Foo' is not assignable to type 'S["a"]'. } } + + // Repro from #31833 + + type Foo1 = { + type: 'foo1'; + extra: number; + }; + + type Foo2 = { + type: 'foo2'; + extra: string; + }; + + type Both = Foo1 | Foo2; + + type FooTypes = Both['type']; + + export type FooFromType = O extends { type: T } ? O : never; + + type FooExtraFromType = FooFromType['extra']; + + function fnWithFooExtra(type: T, extra: FooExtraFromType) { } + + type FnType = (type: T, extra: FooExtraFromType) => void; + + const fn: FnType = fnWithFooExtra; \ No newline at end of file diff --git a/tests/baselines/reference/indexedAccessRelation.js b/tests/baselines/reference/indexedAccessRelation.js index 643200eaf6e25..dfbb70332663b 100644 --- a/tests/baselines/reference/indexedAccessRelation.js +++ b/tests/baselines/reference/indexedAccessRelation.js @@ -17,6 +17,32 @@ class Comp extends Component> this.setState({ a: a }); } } + +// Repro from #31833 + +type Foo1 = { + type: 'foo1'; + extra: number; +}; + +type Foo2 = { + type: 'foo2'; + extra: string; +}; + +type Both = Foo1 | Foo2; + +type FooTypes = Both['type']; + +export type FooFromType = O extends { type: T } ? O : never; + +type FooExtraFromType = FooFromType['extra']; + +function fnWithFooExtra(type: T, extra: FooExtraFromType) { } + +type FnType = (type: T, extra: FooExtraFromType) => void; + +const fn: FnType = fnWithFooExtra; //// [indexedAccessRelation.js] @@ -57,3 +83,5 @@ var Comp = /** @class */ (function (_super) { }; return Comp; }(Component)); +function fnWithFooExtra(type, extra) { } +var fn = fnWithFooExtra; diff --git a/tests/baselines/reference/indexedAccessRelation.symbols b/tests/baselines/reference/indexedAccessRelation.symbols index c64e52a8d4d10..e2d43974203da 100644 --- a/tests/baselines/reference/indexedAccessRelation.symbols +++ b/tests/baselines/reference/indexedAccessRelation.symbols @@ -51,3 +51,80 @@ class Comp extends Component> } } +// Repro from #31833 + +type Foo1 = { +>Foo1 : Symbol(Foo1, Decl(indexedAccessRelation.ts, 17, 1)) + + type: 'foo1'; +>type : Symbol(type, Decl(indexedAccessRelation.ts, 21, 13)) + + extra: number; +>extra : Symbol(extra, Decl(indexedAccessRelation.ts, 22, 15)) + +}; + +type Foo2 = { +>Foo2 : Symbol(Foo2, Decl(indexedAccessRelation.ts, 24, 2)) + + type: 'foo2'; +>type : Symbol(type, Decl(indexedAccessRelation.ts, 26, 13)) + + extra: string; +>extra : Symbol(extra, Decl(indexedAccessRelation.ts, 27, 15)) + +}; + +type Both = Foo1 | Foo2; +>Both : Symbol(Both, Decl(indexedAccessRelation.ts, 29, 2)) +>Foo1 : Symbol(Foo1, Decl(indexedAccessRelation.ts, 17, 1)) +>Foo2 : Symbol(Foo2, Decl(indexedAccessRelation.ts, 24, 2)) + +type FooTypes = Both['type']; +>FooTypes : Symbol(FooTypes, Decl(indexedAccessRelation.ts, 31, 24)) +>Both : Symbol(Both, Decl(indexedAccessRelation.ts, 29, 2)) + +export type FooFromType = O extends { type: T } ? O : never; +>FooFromType : Symbol(FooFromType, Decl(indexedAccessRelation.ts, 33, 29)) +>T : Symbol(T, Decl(indexedAccessRelation.ts, 35, 24)) +>FooTypes : Symbol(FooTypes, Decl(indexedAccessRelation.ts, 31, 24)) +>O : Symbol(O, Decl(indexedAccessRelation.ts, 35, 43)) +>Both : Symbol(Both, Decl(indexedAccessRelation.ts, 29, 2)) +>Both : Symbol(Both, Decl(indexedAccessRelation.ts, 29, 2)) +>O : Symbol(O, Decl(indexedAccessRelation.ts, 35, 43)) +>type : Symbol(type, Decl(indexedAccessRelation.ts, 35, 80)) +>T : Symbol(T, Decl(indexedAccessRelation.ts, 35, 24)) +>O : Symbol(O, Decl(indexedAccessRelation.ts, 35, 43)) + +type FooExtraFromType = FooFromType['extra']; +>FooExtraFromType : Symbol(FooExtraFromType, Decl(indexedAccessRelation.ts, 35, 103)) +>T : Symbol(T, Decl(indexedAccessRelation.ts, 37, 22)) +>FooTypes : Symbol(FooTypes, Decl(indexedAccessRelation.ts, 31, 24)) +>FooFromType : Symbol(FooFromType, Decl(indexedAccessRelation.ts, 33, 29)) +>T : Symbol(T, Decl(indexedAccessRelation.ts, 37, 22)) + +function fnWithFooExtra(type: T, extra: FooExtraFromType) { } +>fnWithFooExtra : Symbol(fnWithFooExtra, Decl(indexedAccessRelation.ts, 37, 68)) +>T : Symbol(T, Decl(indexedAccessRelation.ts, 39, 24)) +>FooTypes : Symbol(FooTypes, Decl(indexedAccessRelation.ts, 31, 24)) +>type : Symbol(type, Decl(indexedAccessRelation.ts, 39, 44)) +>T : Symbol(T, Decl(indexedAccessRelation.ts, 39, 24)) +>extra : Symbol(extra, Decl(indexedAccessRelation.ts, 39, 52)) +>FooExtraFromType : Symbol(FooExtraFromType, Decl(indexedAccessRelation.ts, 35, 103)) +>T : Symbol(T, Decl(indexedAccessRelation.ts, 39, 24)) + +type FnType = (type: T, extra: FooExtraFromType) => void; +>FnType : Symbol(FnType, Decl(indexedAccessRelation.ts, 39, 84)) +>T : Symbol(T, Decl(indexedAccessRelation.ts, 41, 15)) +>FooTypes : Symbol(FooTypes, Decl(indexedAccessRelation.ts, 31, 24)) +>type : Symbol(type, Decl(indexedAccessRelation.ts, 41, 35)) +>T : Symbol(T, Decl(indexedAccessRelation.ts, 41, 15)) +>extra : Symbol(extra, Decl(indexedAccessRelation.ts, 41, 43)) +>FooExtraFromType : Symbol(FooExtraFromType, Decl(indexedAccessRelation.ts, 35, 103)) +>T : Symbol(T, Decl(indexedAccessRelation.ts, 41, 15)) + +const fn: FnType = fnWithFooExtra; +>fn : Symbol(fn, Decl(indexedAccessRelation.ts, 43, 5)) +>FnType : Symbol(FnType, Decl(indexedAccessRelation.ts, 39, 84)) +>fnWithFooExtra : Symbol(fnWithFooExtra, Decl(indexedAccessRelation.ts, 37, 68)) + diff --git a/tests/baselines/reference/indexedAccessRelation.types b/tests/baselines/reference/indexedAccessRelation.types index 180cff338ccc9..9079cf45d3068 100644 --- a/tests/baselines/reference/indexedAccessRelation.types +++ b/tests/baselines/reference/indexedAccessRelation.types @@ -36,3 +36,54 @@ class Comp extends Component> } } +// Repro from #31833 + +type Foo1 = { +>Foo1 : Foo1 + + type: 'foo1'; +>type : "foo1" + + extra: number; +>extra : number + +}; + +type Foo2 = { +>Foo2 : Foo2 + + type: 'foo2'; +>type : "foo2" + + extra: string; +>extra : string + +}; + +type Both = Foo1 | Foo2; +>Both : Both + +type FooTypes = Both['type']; +>FooTypes : "foo1" | "foo2" + +export type FooFromType = O extends { type: T } ? O : never; +>FooFromType : FooFromType +>type : T + +type FooExtraFromType = FooFromType['extra']; +>FooExtraFromType : (FooFromType | FooFromType)["extra"] + +function fnWithFooExtra(type: T, extra: FooExtraFromType) { } +>fnWithFooExtra : (type: T, extra: (FooFromType | FooFromType)["extra"]) => void +>type : T +>extra : (FooFromType | FooFromType)["extra"] + +type FnType = (type: T, extra: FooExtraFromType) => void; +>FnType : FnType +>type : T +>extra : (FooFromType | FooFromType)["extra"] + +const fn: FnType = fnWithFooExtra; +>fn : FnType +>fnWithFooExtra : (type: T, extra: (FooFromType | FooFromType)["extra"]) => void + diff --git a/tests/cases/compiler/indexedAccessRelation.ts b/tests/cases/compiler/indexedAccessRelation.ts index ccfcd559e2047..295979b45ae71 100644 --- a/tests/cases/compiler/indexedAccessRelation.ts +++ b/tests/cases/compiler/indexedAccessRelation.ts @@ -16,3 +16,29 @@ class Comp extends Component> this.setState({ a: a }); } } + +// Repro from #31833 + +type Foo1 = { + type: 'foo1'; + extra: number; +}; + +type Foo2 = { + type: 'foo2'; + extra: string; +}; + +type Both = Foo1 | Foo2; + +type FooTypes = Both['type']; + +export type FooFromType = O extends { type: T } ? O : never; + +type FooExtraFromType = FooFromType['extra']; + +function fnWithFooExtra(type: T, extra: FooExtraFromType) { } + +type FnType = (type: T, extra: FooExtraFromType) => void; + +const fn: FnType = fnWithFooExtra;