-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Fixed contextual types within generic tuple mapped types #53042
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
7150d68
d4b516d
67fa8d5
eef042a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28943,7 +28943,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); | ||
|
|
@@ -28959,6 +28959,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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Erm, |
||
| if (propType) { | ||
| return propType; | ||
| } | ||
| } | ||
| } | ||
| const restType = getElementTypeOfSliceOfTupleType(t, t.target.fixedLength, /*endSkipCount*/ 0, /*writing*/ false, /*noReductions*/ true); | ||
| if (restType) { | ||
| return restType; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| === tests/cases/compiler/contextuallyTypedElementsOfGenericZippingTuples.ts === | ||
| declare function test<T extends unknown[], T2 extends unknown[]>( | ||
| >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)) | ||
|
|
||
| }, | ||
| }, | ||
| ] | ||
| ); | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| === tests/cases/compiler/contextuallyTypedElementsOfGenericZippingTuples.ts === | ||
| declare function test<T extends unknown[], T2 extends unknown[]>( | ||
| >test : <T extends unknown[], T2 extends unknown[]>(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 : <T extends unknown[], T2 extends unknown[]>(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) => string; }, { consume: (arg: number) => number; }] | ||
| { | ||
| >{ consume: (arg) => { const received: string = arg; return received; }, } : { consume: (arg: string) => string; } | ||
|
|
||
| consume: (arg) => { | ||
| >consume : (arg: string) => string | ||
| >(arg) => { const received: string = arg; return received; } : (arg: string) => string | ||
| >arg : string | ||
|
|
||
| const received: string = arg; | ||
| >received : string | ||
| >arg : string | ||
|
|
||
| return received; | ||
| >received : string | ||
|
|
||
| }, | ||
| }, | ||
| { | ||
| >{ consume: (arg) => { const received: number = arg; return received; }, } : { consume: (arg: number) => number; } | ||
|
|
||
| consume: (arg) => { | ||
| >consume : (arg: number) => number | ||
| >(arg) => { const received: number = arg; return received; } : (arg: number) => number | ||
| >arg : number | ||
|
|
||
| const received: number = arg; | ||
| >received : number | ||
| >arg : number | ||
|
|
||
| return received; | ||
| >received : number | ||
|
|
||
| }, | ||
| }, | ||
| ] | ||
| ); | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| // @strict: true | ||
| // @noEmit: true | ||
|
|
||
| declare function test<T extends unknown[], T2 extends unknown[]>( | ||
| 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; | ||
| }, | ||
| }, | ||
| ] | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tuple type could be
[...T]whereT extends []and, thus, should not have a contextual type for a numbered element (at all), so I'm not sure checking this field is correct.