diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dfd479127202c..61dc504c48698 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -32284,7 +32284,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) { + function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type): Type | undefined { return mapType(type, t => { if (t.flags & TypeFlags.Intersection) { let types: Type[] | undefined; @@ -32363,6 +32363,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeFromIndexInfosOfContextualType(type: Type, name: __String, nameType: Type | undefined) { if (isTupleType(type) && isNumericLiteralName(name) && +name >= 0) { + if (type.target.combinedFlags & ElementFlags.Variable) { + const restElement = getTypeArguments(type)[type.target.fixedLength]; + if (restElement !== type) { + const propType = getTypeOfPropertyOfContextualType(restElement, name); + if (propType) { + return propType; + } + } + } const restType = getElementTypeOfSliceOfTupleType(type, type.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..dad1c8cf4f492 --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedElementsOfGenericZippingTuples.types @@ -0,0 +1,129 @@ +//// [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; + }, + }, + ] +);