diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 967ad86941b40..0a5499a0a9f79 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29173,7 +29173,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!(getCheckFlags(symbol) & CheckFlags.Mapped && !(symbol as MappedSymbol).links.type && findResolutionCycleStartIndex(symbol, TypeSystemPropertyName.Type) >= 0); } - function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) { + function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type): Type | undefined { return mapType(type, t => { if (isGenericMappedType(t) && !t.declaration.nameType) { const constraint = getConstraintTypeFromMappedType(t); @@ -29189,6 +29189,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isCircularMappedProperty(prop) ? undefined : getTypeOfSymbol(prop); } if (isTupleType(t) && isNumericLiteralName(name) && +name >= 0) { + if (t.target.hasRestElement) { + const restElement = getTypeArguments(t)[t.target.fixedLength]; + if (restElement !== type) { + const propType = getTypeOfPropertyOfContextualType(restElement, name); + if (propType) { + return propType; + } + } + } const restType = getElementTypeOfSliceOfTupleType(t, t.target.fixedLength, /*endSkipCount*/ 0, /*writing*/ false, /*noReductions*/ true); if (restType) { return restType; diff --git a/tests/baselines/reference/contextuallyTypedElementsOfGenericZippingTuples.errors.txt b/tests/baselines/reference/contextuallyTypedElementsOfGenericZippingTuples.errors.txt new file mode 100644 index 0000000000000..4c727f87265e2 --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedElementsOfGenericZippingTuples.errors.txt @@ -0,0 +1,55 @@ +contextuallyTypedElementsOfGenericZippingTuples.ts(30,15): error TS2322: Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. +contextuallyTypedElementsOfGenericZippingTuples.ts(36,15): error TS2322: Type 'string | number' is not assignable to type 'number'. + Type 'string' is not assignable to type 'number'. + + +==== contextuallyTypedElementsOfGenericZippingTuples.ts (2 errors) ==== + declare function test( + a: [ + ...{ + [K in keyof T]: { + produce: (seed: string) => T[K]; + }; + } + ], + b: [ + ...{ + [K in keyof T2]: { + consume: (arg: T[K & keyof T]) => T2[K]; + }; + } + ] + ): void; + + test( + [ + { + produce: () => "", + }, + { + produce: () => 42, + }, + ], + [ + { + consume: (arg) => { + const received: string = arg; + ~~~~~~~~ +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + return received; + }, + }, + { + consume: (arg) => { + const received: number = arg; + ~~~~~~~~ +!!! error TS2322: Type 'string | number' is not assignable to type 'number'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + return received; + }, + }, + ] + ); + \ No newline at end of file diff --git a/tests/baselines/reference/contextuallyTypedElementsOfGenericZippingTuples.symbols b/tests/baselines/reference/contextuallyTypedElementsOfGenericZippingTuples.symbols new file mode 100644 index 0000000000000..a19580768d745 --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedElementsOfGenericZippingTuples.symbols @@ -0,0 +1,94 @@ +//// [tests/cases/compiler/contextuallyTypedElementsOfGenericZippingTuples.ts] //// + +=== contextuallyTypedElementsOfGenericZippingTuples.ts === +declare function test( +>test : Symbol(test, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 0, 0)) +>T : Symbol(T, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 0, 22)) +>T2 : Symbol(T2, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 0, 42)) + + a: [ +>a : Symbol(a, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 0, 65)) + + ...{ + [K in keyof T]: { +>K : Symbol(K, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 3, 7)) +>T : Symbol(T, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 0, 22)) + + produce: (seed: string) => T[K]; +>produce : Symbol(produce, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 3, 23)) +>seed : Symbol(seed, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 4, 18)) +>T : Symbol(T, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 0, 22)) +>K : Symbol(K, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 3, 7)) + + }; + } + ], + b: [ +>b : Symbol(b, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 7, 4)) + + ...{ + [K in keyof T2]: { +>K : Symbol(K, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 10, 7)) +>T2 : Symbol(T2, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 0, 42)) + + consume: (arg: T[K & keyof T]) => T2[K]; +>consume : Symbol(consume, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 10, 24)) +>arg : Symbol(arg, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 11, 18)) +>T : Symbol(T, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 0, 22)) +>K : Symbol(K, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 10, 7)) +>T : Symbol(T, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 0, 22)) +>T2 : Symbol(T2, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 0, 42)) +>K : Symbol(K, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 10, 7)) + + }; + } + ] +): void; + +test( +>test : Symbol(test, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 0, 0)) + + [ + { + produce: () => "", +>produce : Symbol(produce, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 19, 5)) + + }, + { + produce: () => 42, +>produce : Symbol(produce, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 22, 5)) + + }, + ], + [ + { + consume: (arg) => { +>consume : Symbol(consume, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 27, 5)) +>arg : Symbol(arg, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 28, 16)) + + const received: string = arg; +>received : Symbol(received, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 29, 13)) +>arg : Symbol(arg, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 28, 16)) + + return received; +>received : Symbol(received, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 29, 13)) + + }, + }, + { + consume: (arg) => { +>consume : Symbol(consume, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 33, 5)) +>arg : Symbol(arg, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 34, 16)) + + const received: number = arg; +>received : Symbol(received, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 35, 13)) +>arg : Symbol(arg, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 34, 16)) + + return received; +>received : Symbol(received, Decl(contextuallyTypedElementsOfGenericZippingTuples.ts, 35, 13)) + + }, + }, + ] +); + diff --git a/tests/baselines/reference/contextuallyTypedElementsOfGenericZippingTuples.types b/tests/baselines/reference/contextuallyTypedElementsOfGenericZippingTuples.types new file mode 100644 index 0000000000000..bede741ad2c41 --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedElementsOfGenericZippingTuples.types @@ -0,0 +1,96 @@ +//// [tests/cases/compiler/contextuallyTypedElementsOfGenericZippingTuples.ts] //// + +=== contextuallyTypedElementsOfGenericZippingTuples.ts === +declare function test( +>test : (a: [...{ [K in keyof T]: { produce: (seed: string) => T[K]; }; }], b: [...{ [K in keyof T2]: { consume: (arg: T[K & keyof T]) => T2[K]; }; }]) => void + + a: [ +>a : [...{ [K in keyof T]: { produce: (seed: string) => T[K]; }; }] + + ...{ + [K in keyof T]: { + produce: (seed: string) => T[K]; +>produce : (seed: string) => T[K] +>seed : string + + }; + } + ], + b: [ +>b : [...{ [K in keyof T2]: { consume: (arg: T[K & keyof T]) => T2[K]; }; }] + + ...{ + [K in keyof T2]: { + consume: (arg: T[K & keyof T]) => T2[K]; +>consume : (arg: T[K & keyof T]) => T2[K] +>arg : T[K & keyof T] + + }; + } + ] +): void; + +test( +>test( [ { produce: () => "", }, { produce: () => 42, }, ], [ { consume: (arg) => { const received: string = arg; return received; }, }, { consume: (arg) => { const received: number = arg; return received; }, }, ]) : void +>test : (a: [...{ [K in keyof T]: { produce: (seed: string) => T[K]; }; }], b: [...{ [K in keyof T2]: { consume: (arg: T[K & keyof T]) => T2[K]; }; }]) => void + + [ +>[ { produce: () => "", }, { produce: () => 42, }, ] : [{ produce: () => string; }, { produce: () => number; }] + { +>{ produce: () => "", } : { produce: () => string; } + + produce: () => "", +>produce : () => string +>() => "" : () => string +>"" : "" + + }, + { +>{ produce: () => 42, } : { produce: () => number; } + + produce: () => 42, +>produce : () => number +>() => 42 : () => number +>42 : 42 + + }, + ], + [ +>[ { consume: (arg) => { const received: string = arg; return received; }, }, { consume: (arg) => { const received: number = arg; return received; }, }, ] : [{ consume: (arg: string | number) => string; }, { consume: (arg: string | number) => number; }] + { +>{ consume: (arg) => { const received: string = arg; return received; }, } : { consume: (arg: string | number) => string; } + + consume: (arg) => { +>consume : (arg: string | number) => string +>(arg) => { const received: string = arg; return received; } : (arg: string | number) => string +>arg : string | number + + const received: string = arg; +>received : string +>arg : string | number + + return received; +>received : string + + }, + }, + { +>{ consume: (arg) => { const received: number = arg; return received; }, } : { consume: (arg: string | number) => number; } + + consume: (arg) => { +>consume : (arg: string | number) => number +>(arg) => { const received: number = arg; return received; } : (arg: string | number) => number +>arg : string | number + + const received: number = arg; +>received : number +>arg : string | number + + return received; +>received : number + + }, + }, + ] +); + diff --git a/tests/cases/compiler/contextuallyTypedElementsOfGenericZippingTuples.ts b/tests/cases/compiler/contextuallyTypedElementsOfGenericZippingTuples.ts new file mode 100644 index 0000000000000..a011321a263cc --- /dev/null +++ b/tests/cases/compiler/contextuallyTypedElementsOfGenericZippingTuples.ts @@ -0,0 +1,44 @@ +// @strict: true +// @noEmit: true + +declare function test( + a: [ + ...{ + [K in keyof T]: { + produce: (seed: string) => T[K]; + }; + } + ], + b: [ + ...{ + [K in keyof T2]: { + consume: (arg: T[K & keyof T]) => T2[K]; + }; + } + ] +): void; + +test( + [ + { + produce: () => "", + }, + { + produce: () => 42, + }, + ], + [ + { + consume: (arg) => { + const received: string = arg; + return received; + }, + }, + { + consume: (arg) => { + const received: number = arg; + return received; + }, + }, + ] +);