From b16cc5c254eff956d5df9053e20ac2d56822e7cc Mon Sep 17 00:00:00 2001 From: yusufyildiz34 Date: Fri, 6 Nov 2026 14:15:15 -0500 Subject: [PATCH 1/2] Fix constraint of indexed access on intersections of generic mapped types The constraint of (Record & Record)[K1] was computed by resolving K1 to its constraint string, which made every generic mapped type in the intersection contribute its template type. This gave the constraint T & U and made Record & Record assignable to Record. Mapped types not known to contain the index are now dropped before the index is widened, and mapped types that contain the index but not its generic constraint keep their template type. Fixes #64495 --- tsc/internal/checker/checker.go | 79 +++ ...RecordIntersectionAssignability.errors.txt | 207 +++++++ ...ricRecordIntersectionAssignability.symbols | 512 ++++++++++++++++++ ...nericRecordIntersectionAssignability.types | 307 +++++++++++ .../genericRecordIntersectionAssignability.ts | 93 ++++ 5 files changed, 1198 insertions(+) create mode 100644 tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.types create mode 100644 tsc/testdata/tests/cases/compiler/genericRecordIntersectionAssignability.ts diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 950b9a8e30fb8..727587de37e91 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -17675,6 +17675,9 @@ func (c *Checker) getConstraintFromIndexedAccess(t *Type) *Type { // we substitute an instantiation of E where P is replaced with X. return c.substituteIndexedMappedType(d.objectType, d.indexType) } + if constraint := c.getConstraintOfMappedTypeIntersectionIndexedAccess(t); constraint != nil { + return constraint + } indexConstraint := c.getSimplifiedTypeOrConstraint(d.indexType) if indexConstraint != nil && indexConstraint != d.indexType { indexedAccess := c.getIndexedAccessTypeOrUndefined(d.objectType, indexConstraint, d.accessFlags, nil, nil) @@ -17689,6 +17692,79 @@ func (c *Checker) getConstraintFromIndexedAccess(t *Type) *Type { return nil } +// For an indexed access (A & B)[X] with a generic index X, a generic mapped type { [P in K]: E } in the intersection only +// contributes E for keys in K. Resolving X to a non-generic constraint (e.g. string) would make every such mapped type +// contribute E, giving (Record & Record)[K1] the constraint T & U instead of T, so we first drop the mapped +// types not known to contain X. Resolving X to a generic constraint C is sound since these rules apply again to +// (A & B)[C], but we retain E for the mapped types known to contain X and not C, as they would otherwise be dropped. +// Possibly numeric keys are excluded, as they may select the same properties as differently represented string keys. +func (c *Checker) getConstraintOfMappedTypeIntersectionIndexedAccess(t *Type) *Type { + d := t.AsIndexedAccessType() + if d.objectType.flags&TypeFlagsIntersection == 0 || !c.isGenericIndexType(d.indexType) || c.isPossiblyNumericKeyType(d.indexType) { + return nil + } + types := d.objectType.Types() + if !core.Some(types, c.isGenericMappedType) || core.Some(types, func(s *Type) bool { + return c.isGenericMappedType(s) && c.isPossiblyNumericKeyType(c.getIndexType(s)) + }) { + return nil + } + indexConstraint := c.getSimplifiedTypeOrConstraint(d.indexType) + if indexConstraint == nil || indexConstraint == d.indexType { + return nil + } + if c.isGenericIndexType(indexConstraint) { + var retainedTypes []*Type + for _, s := range types { + if c.isGenericMappedType(s) && c.isKnownKeyOfType(d.indexType, s) && !c.isKnownKeyOfType(indexConstraint, s) { + retainedTypes = append(retainedTypes, c.getSimplifiedType(c.getIndexedAccessTypeEx(s, d.indexType, d.accessFlags, nil, nil), false /*writing*/)) + } + } + if len(retainedTypes) == 0 { + return nil + } + return c.getIntersectionType(append(retainedTypes, c.getIndexedAccessTypeEx(d.objectType, indexConstraint, d.accessFlags, nil, nil))) + } + // For a union constraint, we resolve each constituent separately, as different members of the intersection may + // contain different constituents. For example, given X extends "a" | "b", only { b: U } contains "b" in + // (Record & { b: U })[X]. Otherwise, we index the remaining members by X itself. + changed := false + result := c.mapType(indexConstraint, func(key *Type) *Type { + remainingTypes := core.Filter(types, func(s *Type) bool { + return !c.isGenericMappedType(s) || c.isKnownKeyOfType(d.indexType, s) || c.isKnownKeyOfType(key, s) + }) + if len(remainingTypes) == 0 || len(remainingTypes) == len(types) { + return c.getIndexedAccessTypeEx(d.objectType, key, d.accessFlags, nil, nil) + } + changed = true + return c.getIndexedAccessTypeEx(c.getIntersectionType(remainingTypes), core.IfElse(indexConstraint.flags&TypeFlagsUnion != 0, key, d.indexType), d.accessFlags, nil, nil) + }) + if !changed { + return nil + } + return result +} + +func (c *Checker) isPossiblyNumericKeyType(t *Type) bool { + return c.maybeTypeOfKind(c.getBaseConstraintOrType(t), TypeFlagsNumberLike) +} + +// Return true if the given index type is known to be a key of the given type. A string key and its template literal +// representation (e.g. K and `${K}`) select the same properties, so we also compare those representations. +func (c *Checker) isKnownKeyOfType(indexType *Type, t *Type) bool { + keyType := c.getIndexType(t) + return c.isTypeAssignableTo(indexType, keyType) || c.isTypeAssignableTo(c.getTemplateLiteralKeyType(indexType), c.getTemplateLiteralKeyType(keyType)) +} + +func (c *Checker) getTemplateLiteralKeyType(t *Type) *Type { + return c.mapType(t, func(t *Type) *Type { + if c.isTypeAssignableToKind(t, TypeFlagsStringLike) { + return c.getTemplateLiteralType([]string{"", ""}, []*Type{t}) + } + return t + }) +} + func (c *Checker) getConstraintOfConditionalType(t *Type) *Type { if c.hasNonCircularBaseConstraint(t) { return c.getConstraintFromConditionalType(t) @@ -28333,6 +28409,9 @@ func (c *Checker) computeBaseConstraint(t *Type, stack []RecursionId) *Type { // we substitute an instantiation of E where P is replaced with X. return c.getNextBaseConstraint(c.substituteIndexedMappedType(t.AsIndexedAccessType().objectType, t.AsIndexedAccessType().indexType), stack) } + if constraint := c.getConstraintOfMappedTypeIntersectionIndexedAccess(t); constraint != nil { + return c.getNextBaseConstraint(constraint, stack) + } baseObjectType := c.getNextBaseConstraint(t.AsIndexedAccessType().objectType, stack) baseIndexType := c.getNextBaseConstraint(t.AsIndexedAccessType().indexType, stack) if baseObjectType == nil || baseIndexType == nil { diff --git a/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.errors.txt b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.errors.txt new file mode 100644 index 0000000000000..726cfb1e6833b --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.errors.txt @@ -0,0 +1,207 @@ +genericRecordIntersectionAssignability.ts(4,5): error TS2322: Type 'Record & Record' is not assignable to type 'Record'. +genericRecordIntersectionAssignability.ts(18,11): error TS2322: Type '(Record & Record)[K1]' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'U'. + 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. +genericRecordIntersectionAssignability.ts(19,11): error TS2322: Type '(Record & Record)[K2]' is not assignable to type 'T & U'. + Type 'U' is not assignable to type 'T & U'. + Type 'U' is not assignable to type 'T'. + 'T' could be instantiated with an arbitrary type which could be unrelated to 'U'. +genericRecordIntersectionAssignability.ts(24,11): error TS2339: Property 'b' does not exist on type '(Record & Record)[K1]'. +genericRecordIntersectionAssignability.ts(25,11): error TS2339: Property 'a' does not exist on type '(Record & Record)[K2]'. +genericRecordIntersectionAssignability.ts(33,11): error TS2322: Type '(Record & Record)[K1]' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'U'. + 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. +genericRecordIntersectionAssignability.ts(38,11): error TS2322: Type '(Record & Record & { extra: V; })[K1]' is not assignable to type 'T & U'. + Type '(Record & { extra: V; })[K1]' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'U'. + 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. +genericRecordIntersectionAssignability.ts(43,11): error TS2322: Type '(Record & Record & { [key: string]: V; })[K1]' is not assignable to type 'T & U'. + Type '(Record & { [key: string]: V; })[K1]' is not assignable to type 'T & U'. + Type 'T & V' is not assignable to type 'T & U'. + Type 'T & V' is not assignable to type 'U'. + 'U' could be instantiated with an arbitrary type which could be unrelated to 'T & V'. +genericRecordIntersectionAssignability.ts(56,11): error TS2322: Type '(Record & { a: T; })[K]' is not assignable to type 'T & U'. + Type '{ a: T; }[K]' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'U'. + 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. +genericRecordIntersectionAssignability.ts(72,5): error TS2322: Type '({ [P in `${X}`]: P; } & Record)[X]' is not assignable to type 'X'. + '({ [P in `${X}`]: P; } & Record)[X]' is assignable to the constraint of type 'X', but 'X' could be instantiated with a different subtype of constraint 'number'. + Type '({ [P in `${X}`]: P; } & Record)[K]' is not assignable to type 'X'. + '({ [P in `${X}`]: P; } & Record)[K]' is assignable to the constraint of type 'X', but 'X' could be instantiated with a different subtype of constraint 'number'. + Type 'number' is not assignable to type 'X'. + 'number' is assignable to the constraint of type 'X', but 'X' could be instantiated with a different subtype of constraint 'number'. +genericRecordIntersectionAssignability.ts(89,11): error TS2322: Type '(Record & Record & { b: T; })[X]' is not assignable to type 'T & U'. + Type '(Record & Record & { b: T; })[K1] | (T & U)' is not assignable to type 'T & U'. + Type '(Record & Record & { b: T; })[K1]' is not assignable to type 'T & U'. + Type '(Record & { b: T; })[K1]' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'U'. + 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. + + +==== genericRecordIntersectionAssignability.ts (11 errors) ==== + // https://github.com/microsoft/TypeScript/issues/64495 + + function f1(x: Record & Record): Record { + return x; // Error + ~~~~~~ +!!! error TS2322: Type 'Record & Record' is not assignable to type 'Record'. + } + + function f2(x: Record & Record): Record { + return x; + } + + function f3(x: Record & Record): Record { + return x; + } + + function f4(x: Record & Record, k1: K1, k2: K2) { + const t: T = x[k1]; + const u: U = x[k2]; + const tu1: T & U = x[k1]; // Error + ~~~ +!!! error TS2322: Type '(Record & Record)[K1]' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. +!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. +!!! related TS2208 genericRecordIntersectionAssignability.ts:15:32: This type parameter might need an `extends U` constraint. +!!! related TS2208 genericRecordIntersectionAssignability.ts:15:32: This type parameter might need an `extends U` constraint. + const tu2: T & U = x[k2]; // Error + ~~~ +!!! error TS2322: Type '(Record & Record)[K2]' is not assignable to type 'T & U'. +!!! error TS2322: Type 'U' is not assignable to type 'T & U'. +!!! error TS2322: Type 'U' is not assignable to type 'T'. +!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'U'. +!!! related TS2208 genericRecordIntersectionAssignability.ts:15:54: This type parameter might need an `extends T` constraint. +!!! related TS2208 genericRecordIntersectionAssignability.ts:15:54: This type parameter might need an `extends T` constraint. + } + + function f5(x: Record & Record, k1: K1, k2: K2) { + x[k1].a; + x[k1].b; // Error + ~ +!!! error TS2339: Property 'b' does not exist on type '(Record & Record)[K1]'. + x[k2].a; // Error + ~ +!!! error TS2339: Property 'a' does not exist on type '(Record & Record)[K2]'. + x[k2].b; + } + + function f6(x: Record & Record, k1: K1, k2: K2) { + const t: T = x[k2]; + const u: U = x[k2]; + const tu: T & U = x[k2]; + const tu1: T & U = x[k1]; // Error + ~~~ +!!! error TS2322: Type '(Record & Record)[K1]' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. +!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. +!!! related TS2208 genericRecordIntersectionAssignability.ts:29:32: This type parameter might need an `extends U` constraint. +!!! related TS2208 genericRecordIntersectionAssignability.ts:29:32: This type parameter might need an `extends U` constraint. + } + + function f7(x: Record & Record & { extra: V }, k1: K1) { + const t: T = x[k1]; + const tu: T & U = x[k1]; // Error + ~~ +!!! error TS2322: Type '(Record & Record & { extra: V; })[K1]' is not assignable to type 'T & U'. +!!! error TS2322: Type '(Record & { extra: V; })[K1]' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. +!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. +!!! related TS2208 genericRecordIntersectionAssignability.ts:36:32: This type parameter might need an `extends U` constraint. +!!! related TS2208 genericRecordIntersectionAssignability.ts:36:32: This type parameter might need an `extends U` constraint. +!!! related TS2208 genericRecordIntersectionAssignability.ts:36:32: This type parameter might need an `extends U` constraint. + } + + function f8(x: Record & Record & { [key: string]: V }, k1: K1) { + const tv: T & V = x[k1]; + const tu: T & U = x[k1]; // Error + ~~ +!!! error TS2322: Type '(Record & Record & { [key: string]: V; })[K1]' is not assignable to type 'T & U'. +!!! error TS2322: Type '(Record & { [key: string]: V; })[K1]' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T & V' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T & V' is not assignable to type 'U'. +!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T & V'. + } + + function f9(x: Record & Record & Record, k3: K3) { + const n: number = x[k3]; + } + + function f10(x: Record & Record & Record, k1: K1) { + const tv: T & V = x[k1]; + } + + function f11(x: Record & { a: T }, k: K) { + const t: T = x[k]; + const tu: T & U = x[k]; // Error + ~~ +!!! error TS2322: Type '(Record & { a: T; })[K]' is not assignable to type 'T & U'. +!!! error TS2322: Type '{ a: T; }[K]' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. +!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. +!!! related TS2208 genericRecordIntersectionAssignability.ts:54:29: This type parameter might need an `extends U` constraint. +!!! related TS2208 genericRecordIntersectionAssignability.ts:54:29: This type parameter might need an `extends U` constraint. +!!! related TS2208 genericRecordIntersectionAssignability.ts:54:29: This type parameter might need an `extends U` constraint. + } + + function f12(x: Record & { metadata: number }, k: X): T | U { + return x[k]; + } + + function f13(x: Record & Record<`${K}`, T>, k: K): T { + return x[k]; + } + + function f14(x: Record & Record<`${K}`, unknown>, k: `${K}`): number { + return x[k]; + } + + function f15(x: { [P in `${X}`]: P } & Record, k: X): X { + return x[k]; // Error + ~~~~~~ +!!! error TS2322: Type '({ [P in `${X}`]: P; } & Record)[X]' is not assignable to type 'X'. +!!! error TS2322: '({ [P in `${X}`]: P; } & Record)[X]' is assignable to the constraint of type 'X', but 'X' could be instantiated with a different subtype of constraint 'number'. +!!! error TS2322: Type '({ [P in `${X}`]: P; } & Record)[K]' is not assignable to type 'X'. +!!! error TS2322: '({ [P in `${X}`]: P; } & Record)[K]' is assignable to the constraint of type 'X', but 'X' could be instantiated with a different subtype of constraint 'number'. +!!! error TS2322: Type 'number' is not assignable to type 'X'. +!!! error TS2322: 'number' is assignable to the constraint of type 'X', but 'X' could be instantiated with a different subtype of constraint 'number'. + } + + function f16(x: Record & Record<`${K}`, number>, k: K): number { + return x[k]; + } + + function f17(x: Record & Record<`${X}`, number>, k: X): number { + return x[k]; + } + + function f18(x: Record & { b: number }, k: X): number { + return x[k]; + } + + function f19(x: Record & Record & { b: T }, k: X) { + const t: T = x[k]; + const tu: T & U = x[k]; // Error + ~~ +!!! error TS2322: Type '(Record & Record & { b: T; })[X]' is not assignable to type 'T & U'. +!!! error TS2322: Type '(Record & Record & { b: T; })[K1] | (T & U)' is not assignable to type 'T & U'. +!!! error TS2322: Type '(Record & Record & { b: T; })[K1]' is not assignable to type 'T & U'. +!!! error TS2322: Type '(Record & { b: T; })[K1]' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. +!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. +!!! related TS2208 genericRecordIntersectionAssignability.ts:87:33: This type parameter might need an `extends U` constraint. +!!! related TS2208 genericRecordIntersectionAssignability.ts:87:33: This type parameter might need an `extends U` constraint. +!!! related TS2208 genericRecordIntersectionAssignability.ts:87:33: This type parameter might need an `extends U` constraint. +!!! related TS2208 genericRecordIntersectionAssignability.ts:87:33: This type parameter might need an `extends U` constraint. + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.symbols b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.symbols new file mode 100644 index 0000000000000..3b94f8f666e8c --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.symbols @@ -0,0 +1,512 @@ +//// [tests/cases/compiler/genericRecordIntersectionAssignability.ts] //// + +=== genericRecordIntersectionAssignability.ts === +// https://github.com/microsoft/TypeScript/issues/64495 + +function f1(x: Record & Record): Record { +>f1 : Symbol(f1, Decl(genericRecordIntersectionAssignability.ts, 0, 0)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 2, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 2, 30)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 2, 33)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 2, 52)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 2, 56)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 2, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 2, 30)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 2, 33)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 2, 52)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 2, 12)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 2, 33)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 2, 30)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 2, 52)) + + return x; // Error +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 2, 56)) +} + +function f2(x: Record & Record): Record { +>f2 : Symbol(f2, Decl(genericRecordIntersectionAssignability.ts, 4, 1)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 6, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 6, 30)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 6, 33)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 6, 52)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 6, 56)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 6, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 6, 30)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 6, 33)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 6, 52)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 6, 12)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 6, 33)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 6, 30)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 6, 52)) + + return x; +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 6, 56)) +} + +function f3(x: Record & Record): Record { +>f3 : Symbol(f3, Decl(genericRecordIntersectionAssignability.ts, 8, 1)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 10, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 10, 29)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 10, 32)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 10, 36)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 10, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 10, 29)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 10, 12)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 10, 32)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 10, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 10, 29)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 10, 32)) + + return x; +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 10, 36)) +} + +function f4(x: Record & Record, k1: K1, k2: K2) { +>f4 : Symbol(f4, Decl(genericRecordIntersectionAssignability.ts, 12, 1)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 14, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 14, 30)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 14, 33)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 14, 52)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 14, 56)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 14, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 14, 30)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 14, 33)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 14, 52)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 14, 89)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 14, 12)) +>k2 : Symbol(k2, Decl(genericRecordIntersectionAssignability.ts, 14, 97)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 14, 33)) + + const t: T = x[k1]; +>t : Symbol(t, Decl(genericRecordIntersectionAssignability.ts, 15, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 14, 30)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 14, 56)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 14, 89)) + + const u: U = x[k2]; +>u : Symbol(u, Decl(genericRecordIntersectionAssignability.ts, 16, 9)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 14, 52)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 14, 56)) +>k2 : Symbol(k2, Decl(genericRecordIntersectionAssignability.ts, 14, 97)) + + const tu1: T & U = x[k1]; // Error +>tu1 : Symbol(tu1, Decl(genericRecordIntersectionAssignability.ts, 17, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 14, 30)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 14, 52)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 14, 56)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 14, 89)) + + const tu2: T & U = x[k2]; // Error +>tu2 : Symbol(tu2, Decl(genericRecordIntersectionAssignability.ts, 18, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 14, 30)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 14, 52)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 14, 56)) +>k2 : Symbol(k2, Decl(genericRecordIntersectionAssignability.ts, 14, 97)) +} + +function f5(x: Record & Record, k1: K1, k2: K2) { +>f5 : Symbol(f5, Decl(genericRecordIntersectionAssignability.ts, 19, 1)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 21, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 21, 30)) +>a : Symbol(a, Decl(genericRecordIntersectionAssignability.ts, 21, 42)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 21, 55)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 21, 74)) +>b : Symbol(b, Decl(genericRecordIntersectionAssignability.ts, 21, 86)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 21, 100)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 21, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 21, 30)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 21, 55)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 21, 74)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 21, 133)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 21, 12)) +>k2 : Symbol(k2, Decl(genericRecordIntersectionAssignability.ts, 21, 141)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 21, 55)) + + x[k1].a; +>x[k1].a : Symbol(a, Decl(genericRecordIntersectionAssignability.ts, 21, 42)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 21, 100)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 21, 133)) +>a : Symbol(a, Decl(genericRecordIntersectionAssignability.ts, 21, 42)) + + x[k1].b; // Error +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 21, 100)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 21, 133)) + + x[k2].a; // Error +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 21, 100)) +>k2 : Symbol(k2, Decl(genericRecordIntersectionAssignability.ts, 21, 141)) + + x[k2].b; +>x[k2].b : Symbol(b, Decl(genericRecordIntersectionAssignability.ts, 21, 86)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 21, 100)) +>k2 : Symbol(k2, Decl(genericRecordIntersectionAssignability.ts, 21, 141)) +>b : Symbol(b, Decl(genericRecordIntersectionAssignability.ts, 21, 86)) +} + +function f6(x: Record & Record, k1: K1, k2: K2) { +>f6 : Symbol(f6, Decl(genericRecordIntersectionAssignability.ts, 26, 1)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 28, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 28, 30)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 28, 33)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 28, 12)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 28, 48)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 28, 52)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 28, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 28, 30)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 28, 33)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 28, 48)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 28, 85)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 28, 12)) +>k2 : Symbol(k2, Decl(genericRecordIntersectionAssignability.ts, 28, 93)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 28, 33)) + + const t: T = x[k2]; +>t : Symbol(t, Decl(genericRecordIntersectionAssignability.ts, 29, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 28, 30)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 28, 52)) +>k2 : Symbol(k2, Decl(genericRecordIntersectionAssignability.ts, 28, 93)) + + const u: U = x[k2]; +>u : Symbol(u, Decl(genericRecordIntersectionAssignability.ts, 30, 9)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 28, 48)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 28, 52)) +>k2 : Symbol(k2, Decl(genericRecordIntersectionAssignability.ts, 28, 93)) + + const tu: T & U = x[k2]; +>tu : Symbol(tu, Decl(genericRecordIntersectionAssignability.ts, 31, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 28, 30)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 28, 48)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 28, 52)) +>k2 : Symbol(k2, Decl(genericRecordIntersectionAssignability.ts, 28, 93)) + + const tu1: T & U = x[k1]; // Error +>tu1 : Symbol(tu1, Decl(genericRecordIntersectionAssignability.ts, 32, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 28, 30)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 28, 48)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 28, 52)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 28, 85)) +} + +function f7(x: Record & Record & { extra: V }, k1: K1) { +>f7 : Symbol(f7, Decl(genericRecordIntersectionAssignability.ts, 33, 1)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 35, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 35, 30)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 35, 33)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 35, 52)) +>V : Symbol(V, Decl(genericRecordIntersectionAssignability.ts, 35, 55)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 35, 59)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 35, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 35, 30)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 35, 33)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 35, 52)) +>extra : Symbol(extra, Decl(genericRecordIntersectionAssignability.ts, 35, 95)) +>V : Symbol(V, Decl(genericRecordIntersectionAssignability.ts, 35, 55)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 35, 107)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 35, 12)) + + const t: T = x[k1]; +>t : Symbol(t, Decl(genericRecordIntersectionAssignability.ts, 36, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 35, 30)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 35, 59)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 35, 107)) + + const tu: T & U = x[k1]; // Error +>tu : Symbol(tu, Decl(genericRecordIntersectionAssignability.ts, 37, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 35, 30)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 35, 52)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 35, 59)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 35, 107)) +} + +function f8(x: Record & Record & { [key: string]: V }, k1: K1) { +>f8 : Symbol(f8, Decl(genericRecordIntersectionAssignability.ts, 38, 1)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 40, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 40, 30)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 40, 33)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 40, 52)) +>V : Symbol(V, Decl(genericRecordIntersectionAssignability.ts, 40, 55)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 40, 59)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 40, 12)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 40, 30)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 40, 33)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 40, 52)) +>key : Symbol(key, Decl(genericRecordIntersectionAssignability.ts, 40, 97)) +>V : Symbol(V, Decl(genericRecordIntersectionAssignability.ts, 40, 55)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 40, 115)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 40, 12)) + + const tv: T & V = x[k1]; +>tv : Symbol(tv, Decl(genericRecordIntersectionAssignability.ts, 41, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 40, 30)) +>V : Symbol(V, Decl(genericRecordIntersectionAssignability.ts, 40, 55)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 40, 59)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 40, 115)) + + const tu: T & U = x[k1]; // Error +>tu : Symbol(tu, Decl(genericRecordIntersectionAssignability.ts, 42, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 40, 30)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 40, 52)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 40, 59)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 40, 115)) +} + +function f9(x: Record & Record & Record, k3: K3) { +>f9 : Symbol(f9, Decl(genericRecordIntersectionAssignability.ts, 43, 1)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 45, 12)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 45, 30)) +>K3 : Symbol(K3, Decl(genericRecordIntersectionAssignability.ts, 45, 49)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 45, 12)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 45, 30)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 45, 70)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 45, 12)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 45, 30)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K3 : Symbol(K3, Decl(genericRecordIntersectionAssignability.ts, 45, 49)) +>k3 : Symbol(k3, Decl(genericRecordIntersectionAssignability.ts, 45, 135)) +>K3 : Symbol(K3, Decl(genericRecordIntersectionAssignability.ts, 45, 49)) + + const n: number = x[k3]; +>n : Symbol(n, Decl(genericRecordIntersectionAssignability.ts, 46, 9)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 45, 70)) +>k3 : Symbol(k3, Decl(genericRecordIntersectionAssignability.ts, 45, 135)) +} + +function f10(x: Record & Record & Record, k1: K1) { +>f10 : Symbol(f10, Decl(genericRecordIntersectionAssignability.ts, 47, 1)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 49, 13)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 49, 31)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 49, 34)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 49, 53)) +>V : Symbol(V, Decl(genericRecordIntersectionAssignability.ts, 49, 56)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 49, 60)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 49, 13)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 49, 31)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 49, 34)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 49, 53)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>V : Symbol(V, Decl(genericRecordIntersectionAssignability.ts, 49, 56)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 49, 113)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 49, 13)) + + const tv: T & V = x[k1]; +>tv : Symbol(tv, Decl(genericRecordIntersectionAssignability.ts, 50, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 49, 31)) +>V : Symbol(V, Decl(genericRecordIntersectionAssignability.ts, 49, 56)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 49, 60)) +>k1 : Symbol(k1, Decl(genericRecordIntersectionAssignability.ts, 49, 113)) +} + +function f11(x: Record & { a: T }, k: K) { +>f11 : Symbol(f11, Decl(genericRecordIntersectionAssignability.ts, 51, 1)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 53, 13)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 53, 27)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 53, 30)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 53, 49)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 53, 53)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 53, 30)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 53, 49)) +>a : Symbol(a, Decl(genericRecordIntersectionAssignability.ts, 53, 73)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 53, 27)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 53, 81)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 53, 13)) + + const t: T = x[k]; +>t : Symbol(t, Decl(genericRecordIntersectionAssignability.ts, 54, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 53, 27)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 53, 53)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 53, 81)) + + const tu: T & U = x[k]; // Error +>tu : Symbol(tu, Decl(genericRecordIntersectionAssignability.ts, 55, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 53, 27)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 53, 49)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 53, 53)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 53, 81)) +} + +function f12(x: Record & { metadata: number }, k: X): T | U { +>f12 : Symbol(f12, Decl(genericRecordIntersectionAssignability.ts, 56, 1)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 58, 13)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 58, 30)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 58, 13)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 58, 43)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 58, 46)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 58, 50)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 58, 13)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 58, 43)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 58, 46)) +>metadata : Symbol(metadata, Decl(genericRecordIntersectionAssignability.ts, 58, 73)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 58, 93)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 58, 30)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 58, 43)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 58, 46)) + + return x[k]; +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 58, 50)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 58, 93)) +} + +function f13(x: Record & Record<`${K}`, T>, k: K): T { +>f13 : Symbol(f13, Decl(genericRecordIntersectionAssignability.ts, 60, 1)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 62, 13)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 62, 29)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 62, 33)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 62, 13)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 62, 13)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 62, 29)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 62, 75)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 62, 13)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 62, 29)) + + return x[k]; +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 62, 33)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 62, 75)) +} + +function f14(x: Record & Record<`${K}`, unknown>, k: `${K}`): number { +>f14 : Symbol(f14, Decl(genericRecordIntersectionAssignability.ts, 64, 1)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 66, 13)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 66, 30)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 66, 13)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 66, 13)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 66, 77)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 66, 13)) + + return x[k]; +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 66, 30)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 66, 77)) +} + +function f15(x: { [P in `${X}`]: P } & Record, k: X): X { +>f15 : Symbol(f15, Decl(genericRecordIntersectionAssignability.ts, 68, 1)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 70, 13)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 70, 30)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 70, 13)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 70, 44)) +>P : Symbol(P, Decl(genericRecordIntersectionAssignability.ts, 70, 50)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 70, 30)) +>P : Symbol(P, Decl(genericRecordIntersectionAssignability.ts, 70, 50)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 70, 13)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 70, 89)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 70, 30)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 70, 30)) + + return x[k]; // Error +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 70, 44)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 70, 89)) +} + +function f16(x: Record & Record<`${K}`, number>, k: K): number { +>f16 : Symbol(f16, Decl(genericRecordIntersectionAssignability.ts, 72, 1)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 74, 13)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 74, 31)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 74, 13)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 74, 13)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 74, 78)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 74, 13)) + + return x[k]; +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 74, 31)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 74, 78)) +} + +function f17(x: Record & Record<`${X}`, number>, k: X): number { +>f17 : Symbol(f17, Decl(genericRecordIntersectionAssignability.ts, 76, 1)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 78, 13)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 78, 30)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 78, 13)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 78, 44)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 78, 13)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 78, 30)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 78, 91)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 78, 30)) + + return x[k]; +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 78, 44)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 78, 91)) +} + +function f18(x: Record & { b: number }, k: X): number { +>f18 : Symbol(f18, Decl(genericRecordIntersectionAssignability.ts, 80, 1)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 82, 13)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 82, 30)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 82, 52)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 82, 13)) +>b : Symbol(b, Decl(genericRecordIntersectionAssignability.ts, 82, 82)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 82, 95)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 82, 30)) + + return x[k]; +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 82, 52)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 82, 95)) +} + +function f19(x: Record & Record & { b: T }, k: X) { +>f19 : Symbol(f19, Decl(genericRecordIntersectionAssignability.ts, 84, 1)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 86, 13)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 86, 31)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 86, 34)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 86, 53)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 86, 56)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 86, 13)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 86, 77)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 86, 13)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 86, 31)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 86, 34)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 86, 53)) +>b : Symbol(b, Decl(genericRecordIntersectionAssignability.ts, 86, 113)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 86, 31)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 86, 121)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 86, 56)) + + const t: T = x[k]; +>t : Symbol(t, Decl(genericRecordIntersectionAssignability.ts, 87, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 86, 31)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 86, 77)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 86, 121)) + + const tu: T & U = x[k]; // Error +>tu : Symbol(tu, Decl(genericRecordIntersectionAssignability.ts, 88, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 86, 31)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 86, 53)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 86, 77)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 86, 121)) +} + diff --git a/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.types b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.types new file mode 100644 index 0000000000000..fccc5411405e1 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.types @@ -0,0 +1,307 @@ +//// [tests/cases/compiler/genericRecordIntersectionAssignability.ts] //// + +=== genericRecordIntersectionAssignability.ts === +// https://github.com/microsoft/TypeScript/issues/64495 + +function f1(x: Record & Record): Record { +>f1 : (x: Record & Record) => Record +>x : Record & Record + + return x; // Error +>x : Record & Record +} + +function f2(x: Record & Record): Record { +>f2 : (x: Record & Record) => Record +>x : Record & Record + + return x; +>x : Record & Record +} + +function f3(x: Record & Record): Record { +>f3 : (x: Record & Record) => Record +>x : Record & Record + + return x; +>x : Record & Record +} + +function f4(x: Record & Record, k1: K1, k2: K2) { +>f4 : (x: Record & Record, k1: K1, k2: K2) => void +>x : Record & Record +>k1 : K1 +>k2 : K2 + + const t: T = x[k1]; +>t : T +>x[k1] : (Record & Record)[K1] +>x : Record & Record +>k1 : K1 + + const u: U = x[k2]; +>u : U +>x[k2] : (Record & Record)[K2] +>x : Record & Record +>k2 : K2 + + const tu1: T & U = x[k1]; // Error +>tu1 : T & U +>x[k1] : (Record & Record)[K1] +>x : Record & Record +>k1 : K1 + + const tu2: T & U = x[k2]; // Error +>tu2 : T & U +>x[k2] : (Record & Record)[K2] +>x : Record & Record +>k2 : K2 +} + +function f5(x: Record & Record, k1: K1, k2: K2) { +>f5 : (x: Record & Record, k1: K1, k2: K2) => void +>a : string +>b : string +>x : Record & Record +>k1 : K1 +>k2 : K2 + + x[k1].a; +>x[k1].a : string +>x[k1] : (Record & Record)[K1] +>x : Record & Record +>k1 : K1 +>a : string + + x[k1].b; // Error +>x[k1].b : any +>x[k1] : (Record & Record)[K1] +>x : Record & Record +>k1 : K1 +>b : any + + x[k2].a; // Error +>x[k2].a : any +>x[k2] : (Record & Record)[K2] +>x : Record & Record +>k2 : K2 +>a : any + + x[k2].b; +>x[k2].b : string +>x[k2] : (Record & Record)[K2] +>x : Record & Record +>k2 : K2 +>b : string +} + +function f6(x: Record & Record, k1: K1, k2: K2) { +>f6 : (x: Record & Record, k1: K1, k2: K2) => void +>x : Record & Record +>k1 : K1 +>k2 : K2 + + const t: T = x[k2]; +>t : T +>x[k2] : (Record & Record)[K2] +>x : Record & Record +>k2 : K2 + + const u: U = x[k2]; +>u : U +>x[k2] : (Record & Record)[K2] +>x : Record & Record +>k2 : K2 + + const tu: T & U = x[k2]; +>tu : T & U +>x[k2] : (Record & Record)[K2] +>x : Record & Record +>k2 : K2 + + const tu1: T & U = x[k1]; // Error +>tu1 : T & U +>x[k1] : (Record & Record)[K1] +>x : Record & Record +>k1 : K1 +} + +function f7(x: Record & Record & { extra: V }, k1: K1) { +>f7 : (x: Record & Record & { extra: V; }, k1: K1) => void +>x : Record & Record & { extra: V; } +>extra : V +>k1 : K1 + + const t: T = x[k1]; +>t : T +>x[k1] : (Record & Record & { extra: V; })[K1] +>x : Record & Record & { extra: V; } +>k1 : K1 + + const tu: T & U = x[k1]; // Error +>tu : T & U +>x[k1] : (Record & Record & { extra: V; })[K1] +>x : Record & Record & { extra: V; } +>k1 : K1 +} + +function f8(x: Record & Record & { [key: string]: V }, k1: K1) { +>f8 : (x: Record & Record & { [key: string]: V; }, k1: K1) => void +>x : Record & Record & { [key: string]: V; } +>key : string +>k1 : K1 + + const tv: T & V = x[k1]; +>tv : T & V +>x[k1] : (Record & Record & { [key: string]: V; })[K1] +>x : Record & Record & { [key: string]: V; } +>k1 : K1 + + const tu: T & U = x[k1]; // Error +>tu : T & U +>x[k1] : (Record & Record & { [key: string]: V; })[K1] +>x : Record & Record & { [key: string]: V; } +>k1 : K1 +} + +function f9(x: Record & Record & Record, k3: K3) { +>f9 : (x: Record & Record & Record, k3: K3) => void +>x : Record & Record & Record +>k3 : K3 + + const n: number = x[k3]; +>n : number +>x[k3] : (Record & Record & Record)[K3] +>x : Record & Record & Record +>k3 : K3 +} + +function f10(x: Record & Record & Record, k1: K1) { +>f10 : (x: Record & Record & Record, k1: K1) => void +>x : Record & Record & Record +>k1 : K1 + + const tv: T & V = x[k1]; +>tv : T & V +>x[k1] : (Record & Record & Record)[K1] +>x : Record & Record & Record +>k1 : K1 +} + +function f11(x: Record & { a: T }, k: K) { +>f11 : (x: Record & { a: T; }, k: K) => void +>x : Record & { a: T; } +>a : T +>k : K + + const t: T = x[k]; +>t : T +>x[k] : (Record & { a: T; })[K] +>x : Record & { a: T; } +>k : K + + const tu: T & U = x[k]; // Error +>tu : T & U +>x[k] : (Record & { a: T; })[K] +>x : Record & { a: T; } +>k : K +} + +function f12(x: Record & { metadata: number }, k: X): T | U { +>f12 : (x: Record & { metadata: number; }, k: X) => T | U +>x : Record & { metadata: number; } +>metadata : number +>k : X + + return x[k]; +>x[k] : (Record & { metadata: number; })[X] +>x : Record & { metadata: number; } +>k : X +} + +function f13(x: Record & Record<`${K}`, T>, k: K): T { +>f13 : (x: Record & Record<`${K}`, T>, k: K) => T +>x : Record & Record<`${K}`, T> +>k : K + + return x[k]; +>x[k] : (Record & Record<`${K}`, T>)[K] +>x : Record & Record<`${K}`, T> +>k : K +} + +function f14(x: Record & Record<`${K}`, unknown>, k: `${K}`): number { +>f14 : (x: Record & Record<`${K}`, unknown>, k: `${K}`) => number +>x : Record & Record<`${K}`, unknown> +>k : `${K}` + + return x[k]; +>x[k] : (Record & Record<`${K}`, unknown>)[`${K}`] +>x : Record & Record<`${K}`, unknown> +>k : `${K}` +} + +function f15(x: { [P in `${X}`]: P } & Record, k: X): X { +>f15 : (x: { [P in `${X}`]: P; } & Record, k: X) => X +>x : { [P in `${X}`]: P; } & Record +>k : X + + return x[k]; // Error +>x[k] : ({ [P in `${X}`]: P; } & Record)[X] +>x : { [P in `${X}`]: P; } & Record +>k : X +} + +function f16(x: Record & Record<`${K}`, number>, k: K): number { +>f16 : (x: Record & Record<`${K}`, number>, k: K) => number +>x : Record & Record<`${K}`, number> +>k : K + + return x[k]; +>x[k] : (Record & Record<`${K}`, number>)[K] +>x : Record & Record<`${K}`, number> +>k : K +} + +function f17(x: Record & Record<`${X}`, number>, k: X): number { +>f17 : (x: Record & Record<`${X}`, number>, k: X) => number +>x : Record & Record<`${X}`, number> +>k : X + + return x[k]; +>x[k] : (Record & Record<`${X}`, number>)[X] +>x : Record & Record<`${X}`, number> +>k : X +} + +function f18(x: Record & { b: number }, k: X): number { +>f18 : (x: Record & { b: number; }, k: X) => number +>x : Record<"a" | K, number> & { b: number; } +>b : number +>k : X + + return x[k]; +>x[k] : (Record<"a" | K, number> & { b: number; })[X] +>x : Record<"a" | K, number> & { b: number; } +>k : X +} + +function f19(x: Record & Record & { b: T }, k: X) { +>f19 : (x: Record & Record & { b: T; }, k: X) => void +>x : Record & Record & { b: T; } +>b : T +>k : X + + const t: T = x[k]; +>t : T +>x[k] : (Record & Record & { b: T; })[X] +>x : Record & Record & { b: T; } +>k : X + + const tu: T & U = x[k]; // Error +>tu : T & U +>x[k] : (Record & Record & { b: T; })[X] +>x : Record & Record & { b: T; } +>k : X +} + diff --git a/tsc/testdata/tests/cases/compiler/genericRecordIntersectionAssignability.ts b/tsc/testdata/tests/cases/compiler/genericRecordIntersectionAssignability.ts new file mode 100644 index 0000000000000..57b557d525a4f --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/genericRecordIntersectionAssignability.ts @@ -0,0 +1,93 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/64495 + +function f1(x: Record & Record): Record { + return x; // Error +} + +function f2(x: Record & Record): Record { + return x; +} + +function f3(x: Record & Record): Record { + return x; +} + +function f4(x: Record & Record, k1: K1, k2: K2) { + const t: T = x[k1]; + const u: U = x[k2]; + const tu1: T & U = x[k1]; // Error + const tu2: T & U = x[k2]; // Error +} + +function f5(x: Record & Record, k1: K1, k2: K2) { + x[k1].a; + x[k1].b; // Error + x[k2].a; // Error + x[k2].b; +} + +function f6(x: Record & Record, k1: K1, k2: K2) { + const t: T = x[k2]; + const u: U = x[k2]; + const tu: T & U = x[k2]; + const tu1: T & U = x[k1]; // Error +} + +function f7(x: Record & Record & { extra: V }, k1: K1) { + const t: T = x[k1]; + const tu: T & U = x[k1]; // Error +} + +function f8(x: Record & Record & { [key: string]: V }, k1: K1) { + const tv: T & V = x[k1]; + const tu: T & U = x[k1]; // Error +} + +function f9(x: Record & Record & Record, k3: K3) { + const n: number = x[k3]; +} + +function f10(x: Record & Record & Record, k1: K1) { + const tv: T & V = x[k1]; +} + +function f11(x: Record & { a: T }, k: K) { + const t: T = x[k]; + const tu: T & U = x[k]; // Error +} + +function f12(x: Record & { metadata: number }, k: X): T | U { + return x[k]; +} + +function f13(x: Record & Record<`${K}`, T>, k: K): T { + return x[k]; +} + +function f14(x: Record & Record<`${K}`, unknown>, k: `${K}`): number { + return x[k]; +} + +function f15(x: { [P in `${X}`]: P } & Record, k: X): X { + return x[k]; // Error +} + +function f16(x: Record & Record<`${K}`, number>, k: K): number { + return x[k]; +} + +function f17(x: Record & Record<`${X}`, number>, k: X): number { + return x[k]; +} + +function f18(x: Record & { b: number }, k: X): number { + return x[k]; +} + +function f19(x: Record & Record & { b: T }, k: X) { + const t: T = x[k]; + const tu: T & U = x[k]; // Error +} From 6f0048055e3680ebb41467a1aa0a3754c27ab5e4 Mon Sep 17 00:00:00 2001 From: yusufyildiz34 Date: Fri, 6 Nov 2026 14:27:33 -0500 Subject: [PATCH 2/2] Handle constraint chains and mixed union constraints - Return (A & B)[C] for a generic constraint C even when no templates are retained, so base constraint computation doesn't resolve X directly to its base constraint and bypass the filtering. - Use unknown when no member of the intersection is known to contain the index, instead of falling back to the unfiltered intersection. - Filter the non-generic constituents of a union constraint that also contains generic constituents, such as X extends K1 | "b". --- tsc/internal/checker/checker.go | 44 ++++++----- ...RecordIntersectionAssignability.errors.txt | 55 +++++++++---- ...ricRecordIntersectionAssignability.symbols | 79 +++++++++++++++++++ ...nericRecordIntersectionAssignability.types | 52 ++++++++++++ .../genericRecordIntersectionAssignability.ts | 14 ++++ 5 files changed, 211 insertions(+), 33 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 727587de37e91..79e26f506bd22 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -17713,36 +17713,44 @@ func (c *Checker) getConstraintOfMappedTypeIntersectionIndexedAccess(t *Type) *T if indexConstraint == nil || indexConstraint == d.indexType { return nil } - if c.isGenericIndexType(indexConstraint) { - var retainedTypes []*Type + isGenericConstraint := c.isGenericIndexType(indexConstraint) + var retainedTypes []*Type + if isGenericConstraint { for _, s := range types { if c.isGenericMappedType(s) && c.isKnownKeyOfType(d.indexType, s) && !c.isKnownKeyOfType(indexConstraint, s) { retainedTypes = append(retainedTypes, c.getSimplifiedType(c.getIndexedAccessTypeEx(s, d.indexType, d.accessFlags, nil, nil), false /*writing*/)) } } - if len(retainedTypes) == 0 { - return nil - } - return c.getIntersectionType(append(retainedTypes, c.getIndexedAccessTypeEx(d.objectType, indexConstraint, d.accessFlags, nil, nil))) } - // For a union constraint, we resolve each constituent separately, as different members of the intersection may + // We resolve each non-generic constituent of the constraint separately, as different members of the intersection may // contain different constituents. For example, given X extends "a" | "b", only { b: U } contains "b" in - // (Record & { b: U })[X]. Otherwise, we index the remaining members by X itself. + // (Record & { b: U })[X]. When the constraint isn't a union, we index the remaining members by X itself. + // When no members remain, X isn't known to be a key of any of them, and the constraint is unknown. changed := false - result := c.mapType(indexConstraint, func(key *Type) *Type { - remainingTypes := core.Filter(types, func(s *Type) bool { - return !c.isGenericMappedType(s) || c.isKnownKeyOfType(d.indexType, s) || c.isKnownKeyOfType(key, s) - }) - if len(remainingTypes) == 0 || len(remainingTypes) == len(types) { - return c.getIndexedAccessTypeEx(d.objectType, key, d.accessFlags, nil, nil) + widenedType := c.mapType(indexConstraint, func(key *Type) *Type { + if !c.isGenericIndexType(key) { + remainingTypes := core.Filter(types, func(s *Type) bool { + return !c.isGenericMappedType(s) || c.isKnownKeyOfType(d.indexType, s) || c.isKnownKeyOfType(key, s) + }) + if len(remainingTypes) < len(types) { + changed = true + if len(remainingTypes) == 0 { + return c.unknownType + } + return c.getIndexedAccessTypeEx(c.getIntersectionType(remainingTypes), core.IfElse(indexConstraint.flags&TypeFlagsUnion != 0, key, d.indexType), d.accessFlags, nil, nil) + } } - changed = true - return c.getIndexedAccessTypeEx(c.getIntersectionType(remainingTypes), core.IfElse(indexConstraint.flags&TypeFlagsUnion != 0, key, d.indexType), d.accessFlags, nil, nil) + return c.getIndexedAccessTypeEx(d.objectType, key, d.accessFlags, nil, nil) }) if !changed { - return nil + if !isGenericConstraint { + return nil + } + // We return (A & B)[C] even when nothing changed, such that base constraint computation applies these rules to + // it instead of resolving X to its base constraint directly. + widenedType = c.getIndexedAccessTypeEx(d.objectType, indexConstraint, d.accessFlags, nil, nil) } - return result + return c.getIntersectionType(append(retainedTypes, widenedType)) } func (c *Checker) isPossiblyNumericKeyType(t *Type) bool { diff --git a/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.errors.txt b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.errors.txt index 726cfb1e6833b..ec50a445f92db 100644 --- a/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.errors.txt +++ b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.errors.txt @@ -35,15 +35,20 @@ genericRecordIntersectionAssignability.ts(72,5): error TS2322: Type '({ [P in `$ Type 'number' is not assignable to type 'X'. 'number' is assignable to the constraint of type 'X', but 'X' could be instantiated with a different subtype of constraint 'number'. genericRecordIntersectionAssignability.ts(89,11): error TS2322: Type '(Record & Record & { b: T; })[X]' is not assignable to type 'T & U'. - Type '(Record & Record & { b: T; })[K1] | (T & U)' is not assignable to type 'T & U'. - Type '(Record & Record & { b: T; })[K1]' is not assignable to type 'T & U'. - Type '(Record & { b: T; })[K1]' is not assignable to type 'T & U'. - Type 'T' is not assignable to type 'T & U'. - Type 'T' is not assignable to type 'U'. - 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. + Type 'T | (Record & Record & { b: T; })[K1]' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'U'. + 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. +genericRecordIntersectionAssignability.ts(93,5): error TS2322: Type 'string | number' is not assignable to type 'number'. + Type 'string' is not assignable to type 'number'. +genericRecordIntersectionAssignability.ts(98,10): error TS2339: Property 'b' does not exist on type '(Record & Record)[X]'. +genericRecordIntersectionAssignability.ts(103,11): error TS2322: Type '(Record & Record)[X]' is not assignable to type 'T & U'. + Type 'T & (Record & Record)[K]' is not assignable to type 'T & U'. + Type 'T & (Record & Record)[K]' is not assignable to type 'U'. + 'U' could be instantiated with an arbitrary type which could be unrelated to 'T & (Record & Record)[K]'. -==== genericRecordIntersectionAssignability.ts (11 errors) ==== +==== genericRecordIntersectionAssignability.ts (14 errors) ==== // https://github.com/microsoft/TypeScript/issues/64495 function f1(x: Record & Record): Record { @@ -193,15 +198,35 @@ genericRecordIntersectionAssignability.ts(89,11): error TS2322: Type '(Record & Record & { b: T; })[X]' is not assignable to type 'T & U'. -!!! error TS2322: Type '(Record & Record & { b: T; })[K1] | (T & U)' is not assignable to type 'T & U'. -!!! error TS2322: Type '(Record & Record & { b: T; })[K1]' is not assignable to type 'T & U'. -!!! error TS2322: Type '(Record & { b: T; })[K1]' is not assignable to type 'T & U'. -!!! error TS2322: Type 'T' is not assignable to type 'T & U'. -!!! error TS2322: Type 'T' is not assignable to type 'U'. -!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. -!!! related TS2208 genericRecordIntersectionAssignability.ts:87:33: This type parameter might need an `extends U` constraint. -!!! related TS2208 genericRecordIntersectionAssignability.ts:87:33: This type parameter might need an `extends U` constraint. +!!! error TS2322: Type 'T | (Record & Record & { b: T; })[K1]' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. +!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'. !!! related TS2208 genericRecordIntersectionAssignability.ts:87:33: This type parameter might need an `extends U` constraint. !!! related TS2208 genericRecordIntersectionAssignability.ts:87:33: This type parameter might need an `extends U` constraint. } + + function f20(x: Record & Record & { b: string }, k: X): number { + return x[k]; // Error + ~~~~~~ +!!! error TS2322: Type 'string | number' is not assignable to type 'number'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + } + + function f21(x: Record & Record, k: X) { + x[k].a; + x[k].b; // Error + ~ +!!! error TS2339: Property 'b' does not exist on type '(Record & Record)[X]'. + } + + function f22(x: Record & Record, k: X) { + const t: T = x[k]; + const tu: T & U = x[k]; // Error + ~~ +!!! error TS2322: Type '(Record & Record)[X]' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T & (Record & Record)[K]' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T & (Record & Record)[K]' is not assignable to type 'U'. +!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T & (Record & Record)[K]'. + } \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.symbols b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.symbols index 3b94f8f666e8c..9e8557a109662 100644 --- a/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.symbols +++ b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.symbols @@ -510,3 +510,82 @@ function f19(x: >k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 86, 121)) } +function f20(x: Record & Record & { b: string }, k: X): number { +>f20 : Symbol(f20, Decl(genericRecordIntersectionAssignability.ts, 89, 1)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 91, 13)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 91, 31)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 91, 50)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 91, 13)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 91, 71)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 91, 13)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 91, 31)) +>b : Symbol(b, Decl(genericRecordIntersectionAssignability.ts, 91, 117)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 91, 130)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 91, 50)) + + return x[k]; // Error +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 91, 71)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 91, 130)) +} + +function f21(x: Record & Record, k: X) { +>f21 : Symbol(f21, Decl(genericRecordIntersectionAssignability.ts, 93, 1)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 95, 13)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 95, 31)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 95, 50)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 95, 13)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 95, 65)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K1 : Symbol(K1, Decl(genericRecordIntersectionAssignability.ts, 95, 13)) +>a : Symbol(a, Decl(genericRecordIntersectionAssignability.ts, 95, 80)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K2 : Symbol(K2, Decl(genericRecordIntersectionAssignability.ts, 95, 31)) +>b : Symbol(b, Decl(genericRecordIntersectionAssignability.ts, 95, 108)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 95, 122)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 95, 50)) + + x[k].a; +>x[k].a : Symbol(a, Decl(genericRecordIntersectionAssignability.ts, 95, 80)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 95, 65)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 95, 122)) +>a : Symbol(a, Decl(genericRecordIntersectionAssignability.ts, 95, 80)) + + x[k].b; // Error +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 95, 65)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 95, 122)) +} + +function f22(x: Record & Record, k: X) { +>f22 : Symbol(f22, Decl(genericRecordIntersectionAssignability.ts, 98, 1)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 100, 13)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 100, 30)) +>K : Symbol(K, Decl(genericRecordIntersectionAssignability.ts, 100, 13)) +>L : Symbol(L, Decl(genericRecordIntersectionAssignability.ts, 100, 43)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 100, 61)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 100, 64)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 100, 68)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 100, 30)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 100, 61)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>L : Symbol(L, Decl(genericRecordIntersectionAssignability.ts, 100, 43)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 100, 64)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 100, 99)) +>X : Symbol(X, Decl(genericRecordIntersectionAssignability.ts, 100, 30)) + + const t: T = x[k]; +>t : Symbol(t, Decl(genericRecordIntersectionAssignability.ts, 101, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 100, 61)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 100, 68)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 100, 99)) + + const tu: T & U = x[k]; // Error +>tu : Symbol(tu, Decl(genericRecordIntersectionAssignability.ts, 102, 9)) +>T : Symbol(T, Decl(genericRecordIntersectionAssignability.ts, 100, 61)) +>U : Symbol(U, Decl(genericRecordIntersectionAssignability.ts, 100, 64)) +>x : Symbol(x, Decl(genericRecordIntersectionAssignability.ts, 100, 68)) +>k : Symbol(k, Decl(genericRecordIntersectionAssignability.ts, 100, 99)) +} + diff --git a/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.types b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.types index fccc5411405e1..78b23555672c2 100644 --- a/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.types +++ b/tsc/testdata/baselines/reference/compiler/genericRecordIntersectionAssignability.types @@ -305,3 +305,55 @@ function f19(x: >k : X } +function f20(x: Record & Record & { b: string }, k: X): number { +>f20 : (x: Record & Record & { b: string; }, k: X) => number +>x : Record & Record & { b: string; } +>b : string +>k : X + + return x[k]; // Error +>x[k] : string | number +>x : Record & Record & { b: string; } +>k : X +} + +function f21(x: Record & Record, k: X) { +>f21 : (x: Record & Record, k: X) => void +>x : Record & Record +>a : string +>b : string +>k : X + + x[k].a; +>x[k].a : string +>x[k] : (Record & Record)[X] +>x : Record & Record +>k : X +>a : string + + x[k].b; // Error +>x[k].b : any +>x[k] : (Record & Record)[X] +>x : Record & Record +>k : X +>b : any +} + +function f22(x: Record & Record, k: X) { +>f22 : (x: Record & Record, k: X) => void +>x : Record & Record +>k : X + + const t: T = x[k]; +>t : T +>x[k] : (Record & Record)[X] +>x : Record & Record +>k : X + + const tu: T & U = x[k]; // Error +>tu : T & U +>x[k] : (Record & Record)[X] +>x : Record & Record +>k : X +} + diff --git a/tsc/testdata/tests/cases/compiler/genericRecordIntersectionAssignability.ts b/tsc/testdata/tests/cases/compiler/genericRecordIntersectionAssignability.ts index 57b557d525a4f..fbbe05bc4a40c 100644 --- a/tsc/testdata/tests/cases/compiler/genericRecordIntersectionAssignability.ts +++ b/tsc/testdata/tests/cases/compiler/genericRecordIntersectionAssignability.ts @@ -91,3 +91,17 @@ function f19(x: const t: T = x[k]; const tu: T & U = x[k]; // Error } + +function f20(x: Record & Record & { b: string }, k: X): number { + return x[k]; // Error +} + +function f21(x: Record & Record, k: X) { + x[k].a; + x[k].b; // Error +} + +function f22(x: Record & Record, k: X) { + const t: T = x[k]; + const tu: T & U = x[k]; // Error +}