diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f8cee82c27af3..a4babe380212e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15030,14 +15030,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const modifiersType = getModifiersTypeFromMappedType(type); const baseConstraint = isGenericMappedType(modifiersType) ? getApparentTypeOfMappedType(modifiersType) : getBaseConstraintOfType(modifiersType); if (baseConstraint && everyType(baseConstraint, t => isArrayOrTupleType(t) || isArrayOrTupleOrIntersection(t))) { - return instantiateType(target, prependTypeMapping(typeVariable, baseConstraint, type.mapper)); + const applicableConstraint = baseConstraint.flags & TypeFlags.Intersection ? getIntersectionType(filter((baseConstraint as IntersectionType).types, isArrayOrTupleType)) : baseConstraint; + return instantiateType(target, prependTypeMapping(typeVariable, applicableConstraint, type.mapper)); } } return type; } function isArrayOrTupleOrIntersection(type: Type) { - return !!(type.flags & TypeFlags.Intersection) && every((type as IntersectionType).types, isArrayOrTupleType); + return !!(type.flags & TypeFlags.Intersection) && some((type as IntersectionType).types, isArrayOrTupleType); } function isMappedTypeGenericIndexedAccess(type: Type) { @@ -20383,7 +20384,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return instantiateMappedTupleType(t, type, typeVariable!, mapper); } if (isArrayOrTupleOrIntersection(t)) { - return getIntersectionType(map((t as IntersectionType).types, instantiateConstituent)); + return getIntersectionType(map(filter((t as IntersectionType).types, isArrayOrTupleType), instantiateConstituent)); } } return instantiateAnonymousType(type, prependTypeMapping(typeVariable!, t, mapper)); diff --git a/tests/baselines/reference/mappedArrayTupleIntersections.types b/tests/baselines/reference/mappedArrayTupleIntersections.types index d5e5354d64da2..784df3da504db 100644 --- a/tests/baselines/reference/mappedArrayTupleIntersections.types +++ b/tests/baselines/reference/mappedArrayTupleIntersections.types @@ -28,8 +28,8 @@ type T4 = Boxify; > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type T5 = Boxify; ->T5 : Boxify -> : ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ +>T5 : Box[] +> : ^^^^^^^^^^^^^ >x : string > : ^^^^^^ diff --git a/tests/baselines/reference/mappedArrayTupleIntersections2.symbols b/tests/baselines/reference/mappedArrayTupleIntersections2.symbols new file mode 100644 index 0000000000000..a501d98fb4797 --- /dev/null +++ b/tests/baselines/reference/mappedArrayTupleIntersections2.symbols @@ -0,0 +1,62 @@ +//// [tests/cases/compiler/mappedArrayTupleIntersections2.ts] //// + +=== mappedArrayTupleIntersections2.ts === +// https://github.com/microsoft/TypeScript/issues/59849 + +type IdentitySpread = [...{ [i in keyof t]: t[i] }]; +>IdentitySpread : Symbol(IdentitySpread, Decl(mappedArrayTupleIntersections2.ts, 0, 0)) +>t : Symbol(t, Decl(mappedArrayTupleIntersections2.ts, 2, 20)) +>i : Symbol(i, Decl(mappedArrayTupleIntersections2.ts, 2, 59)) +>t : Symbol(t, Decl(mappedArrayTupleIntersections2.ts, 2, 20)) +>t : Symbol(t, Decl(mappedArrayTupleIntersections2.ts, 2, 20)) +>i : Symbol(i, Decl(mappedArrayTupleIntersections2.ts, 2, 59)) + +type Result1 = IdentitySpread<{ name: string } & string[]>; +>Result1 : Symbol(Result1, Decl(mappedArrayTupleIntersections2.ts, 2, 82)) +>IdentitySpread : Symbol(IdentitySpread, Decl(mappedArrayTupleIntersections2.ts, 0, 0)) +>name : Symbol(name, Decl(mappedArrayTupleIntersections2.ts, 4, 31)) + +type Result2 = IdentitySpread<(string | number)[] & ['foo', string, 42]>; +>Result2 : Symbol(Result2, Decl(mappedArrayTupleIntersections2.ts, 4, 59)) +>IdentitySpread : Symbol(IdentitySpread, Decl(mappedArrayTupleIntersections2.ts, 0, 0)) + +type Result3 = IdentitySpread<[string | boolean, string | symbol, ...number[]] & ['foo', string, 43]>; +>Result3 : Symbol(Result3, Decl(mappedArrayTupleIntersections2.ts, 5, 73)) +>IdentitySpread : Symbol(IdentitySpread, Decl(mappedArrayTupleIntersections2.ts, 0, 0)) + +type Result4 = IdentitySpread<[string | boolean, boolean, ...number[]] & ['foo', string, 44]>; +>Result4 : Symbol(Result4, Decl(mappedArrayTupleIntersections2.ts, 6, 102)) +>IdentitySpread : Symbol(IdentitySpread, Decl(mappedArrayTupleIntersections2.ts, 0, 0)) + +type Box = { value: T }; +>Box : Symbol(Box, Decl(mappedArrayTupleIntersections2.ts, 7, 94)) +>T : Symbol(T, Decl(mappedArrayTupleIntersections2.ts, 9, 9)) +>value : Symbol(value, Decl(mappedArrayTupleIntersections2.ts, 9, 15)) +>T : Symbol(T, Decl(mappedArrayTupleIntersections2.ts, 9, 9)) + +type BoxedSpread = [...{ [i in keyof t]: Box }]; +>BoxedSpread : Symbol(BoxedSpread, Decl(mappedArrayTupleIntersections2.ts, 9, 27)) +>t : Symbol(t, Decl(mappedArrayTupleIntersections2.ts, 10, 17)) +>i : Symbol(i, Decl(mappedArrayTupleIntersections2.ts, 10, 56)) +>t : Symbol(t, Decl(mappedArrayTupleIntersections2.ts, 10, 17)) +>Box : Symbol(Box, Decl(mappedArrayTupleIntersections2.ts, 7, 94)) +>t : Symbol(t, Decl(mappedArrayTupleIntersections2.ts, 10, 17)) +>i : Symbol(i, Decl(mappedArrayTupleIntersections2.ts, 10, 56)) + +type Result5 = BoxedSpread<{ name: string } & string[]>; +>Result5 : Symbol(Result5, Decl(mappedArrayTupleIntersections2.ts, 10, 84)) +>BoxedSpread : Symbol(BoxedSpread, Decl(mappedArrayTupleIntersections2.ts, 9, 27)) +>name : Symbol(name, Decl(mappedArrayTupleIntersections2.ts, 12, 28)) + +type Result6 = BoxedSpread<(string | number)[] & ['foo', string, 42]>; +>Result6 : Symbol(Result6, Decl(mappedArrayTupleIntersections2.ts, 12, 56)) +>BoxedSpread : Symbol(BoxedSpread, Decl(mappedArrayTupleIntersections2.ts, 9, 27)) + +type Result7 = BoxedSpread<[string | boolean, string | symbol, ...number[]] & ['foo', string, 43]>; +>Result7 : Symbol(Result7, Decl(mappedArrayTupleIntersections2.ts, 13, 70)) +>BoxedSpread : Symbol(BoxedSpread, Decl(mappedArrayTupleIntersections2.ts, 9, 27)) + +type Result8 = BoxedSpread<[string | boolean, boolean, ...number[]] & ['foo', string, 44]>; +>Result8 : Symbol(Result8, Decl(mappedArrayTupleIntersections2.ts, 14, 99)) +>BoxedSpread : Symbol(BoxedSpread, Decl(mappedArrayTupleIntersections2.ts, 9, 27)) + diff --git a/tests/baselines/reference/mappedArrayTupleIntersections2.types b/tests/baselines/reference/mappedArrayTupleIntersections2.types new file mode 100644 index 0000000000000..377d3224dca0f --- /dev/null +++ b/tests/baselines/reference/mappedArrayTupleIntersections2.types @@ -0,0 +1,55 @@ +//// [tests/cases/compiler/mappedArrayTupleIntersections2.ts] //// + +=== mappedArrayTupleIntersections2.ts === +// https://github.com/microsoft/TypeScript/issues/59849 + +type IdentitySpread = [...{ [i in keyof t]: t[i] }]; +>IdentitySpread : [...{ [i in keyof t]: t[i]; }] +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ + +type Result1 = IdentitySpread<{ name: string } & string[]>; +>Result1 : string[] +> : ^^^^^^^^ +>name : string +> : ^^^^^^ + +type Result2 = IdentitySpread<(string | number)[] & ['foo', string, 42]>; +>Result2 : (string | 42)[] +> : ^^^^^^^^^^^^^^^ + +type Result3 = IdentitySpread<[string | boolean, string | symbol, ...number[]] & ['foo', string, 43]>; +>Result3 : (string | 43)[] +> : ^^^^^^^^^^^^^^^ + +type Result4 = IdentitySpread<[string | boolean, boolean, ...number[]] & ['foo', string, 44]>; +>Result4 : never +> : ^^^^^ + +type Box = { value: T }; +>Box : Box +> : ^^^^^^ +>value : T +> : ^ + +type BoxedSpread = [...{ [i in keyof t]: Box }]; +>BoxedSpread : [...{ [i in keyof t]: Box; }] +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +type Result5 = BoxedSpread<{ name: string } & string[]>; +>Result5 : Box[] +> : ^^^^^^^^^^^^^ +>name : string +> : ^^^^^^ + +type Result6 = BoxedSpread<(string | number)[] & ['foo', string, 42]>; +>Result6 : (Box & (Box | Box<"foo"> | Box<42>))[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +type Result7 = BoxedSpread<[string | boolean, string | symbol, ...number[]] & ['foo', string, 43]>; +>Result7 : ((Box & Box<"foo">) | (Box & Box) | (Box & Box) | (Box & Box<"foo">) | (Box & Box) | (Box & Box<43>))[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +type Result8 = BoxedSpread<[string | boolean, boolean, ...number[]] & ['foo', string, 44]>; +>Result8 : never +> : ^^^^^ + diff --git a/tests/cases/compiler/mappedArrayTupleIntersections2.ts b/tests/cases/compiler/mappedArrayTupleIntersections2.ts new file mode 100644 index 0000000000000..e555292352c18 --- /dev/null +++ b/tests/cases/compiler/mappedArrayTupleIntersections2.ts @@ -0,0 +1,19 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/59849 + +type IdentitySpread = [...{ [i in keyof t]: t[i] }]; + +type Result1 = IdentitySpread<{ name: string } & string[]>; +type Result2 = IdentitySpread<(string | number)[] & ['foo', string, 42]>; +type Result3 = IdentitySpread<[string | boolean, string | symbol, ...number[]] & ['foo', string, 43]>; +type Result4 = IdentitySpread<[string | boolean, boolean, ...number[]] & ['foo', string, 44]>; + +type Box = { value: T }; +type BoxedSpread = [...{ [i in keyof t]: Box }]; + +type Result5 = BoxedSpread<{ name: string } & string[]>; +type Result6 = BoxedSpread<(string | number)[] & ['foo', string, 42]>; +type Result7 = BoxedSpread<[string | boolean, string | symbol, ...number[]] & ['foo', string, 43]>; +type Result8 = BoxedSpread<[string | boolean, boolean, ...number[]] & ['foo', string, 44]>;