Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28962,6 +28962,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
getContextualTypeForObjectLiteralMethod(node, contextFlags) :
getContextualType(node, contextFlags);
const instantiatedType = instantiateContextualType(contextualType, node, contextFlags);
if (instantiatedType && contextFlags && contextFlags & ContextFlags.DeferGenericIndexedAccess && shouldDeferIndexType(instantiatedType)) {
return instantiatedType;
}
if (instantiatedType && !(contextFlags && contextFlags & ContextFlags.NoConstraints && instantiatedType.flags & TypeFlags.TypeVariable)) {
const apparentType = mapType(instantiatedType, getApparentType, /*noReductions*/ true);
return apparentType.flags & TypeFlags.Union && isObjectLiteralExpression(node) ? discriminateContextualTypeByObjectMembers(node, apparentType as UnionType) :
Expand Down Expand Up @@ -29669,7 +29672,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
let propertiesArray: Symbol[] = [];
let spread: Type = emptyObjectType;

pushContextualType(node, getContextualType(node, /*contextFlags*/ undefined));
pushContextualType(node, getContextualType(node, checkMode && checkMode & CheckMode.Inferential ? ContextFlags.DeferGenericIndexedAccess : undefined));
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5262,6 +5262,7 @@ export const enum ContextFlags {
NoConstraints = 1 << 1, // Don't obtain type variable constraints
Completions = 1 << 2, // Ignore inference to current node and parent nodes out to the containing call for completions
SkipBindingPatterns = 1 << 3, // Ignore contextual types applied by binding patterns
DeferGenericIndexedAccess = 1 << 4, // Defer generic indexed access type instead of resolving it immediately to the constraint
}

// NOTE: If modifying this enum, must modify `TypeFormatFlags` too!
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
=== tests/cases/compiler/contextualSignatureInNestedPropOfGenericIndexedAccess.ts ===
// repro from #52575

export interface Event<T> {
>Event : Symbol(Event, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 0, 0))
>T : Symbol(T, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 2, 23))

callback: (response: T) => void;
>callback : Symbol(Event.callback, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 2, 27))
>response : Symbol(response, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 3, 15))
>T : Symbol(T, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 2, 23))

nested: {
>nested : Symbol(Event.nested, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 3, 36))

nestedCallback: (response: T) => void;
>nestedCallback : Symbol(nestedCallback, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 4, 13))
>response : Symbol(response, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 5, 25))
>T : Symbol(T, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 2, 23))
}
}

export type CustomEvents = {
>CustomEvents : Symbol(CustomEvents, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 7, 1))

a: Event<string>
>a : Symbol(a, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 9, 28))
>Event : Symbol(Event, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 0, 0))

b: Event<number>
>b : Symbol(b, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 10, 20))
>Event : Symbol(Event, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 0, 0))

};

declare function emit<T extends keyof CustomEvents>(type: T, data: CustomEvents[T]): void
>emit : Symbol(emit, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 12, 2))
>T : Symbol(T, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 14, 22))
>CustomEvents : Symbol(CustomEvents, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 7, 1))
>type : Symbol(type, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 14, 52))
>T : Symbol(T, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 14, 22))
>data : Symbol(data, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 14, 60))
>CustomEvents : Symbol(CustomEvents, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 7, 1))
>T : Symbol(T, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 14, 22))

emit('a', {
>emit : Symbol(emit, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 12, 2))

callback: (r) => {},
>callback : Symbol(callback, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 16, 11))
>r : Symbol(r, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 17, 15))

nested: {
>nested : Symbol(nested, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 17, 24))

nestedCallback: (r) => {},
>nestedCallback : Symbol(nestedCallback, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 18, 13))
>r : Symbol(r, Decl(contextualSignatureInNestedPropOfGenericIndexedAccess.ts, 19, 25))

},
});

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
=== tests/cases/compiler/contextualSignatureInNestedPropOfGenericIndexedAccess.ts ===
// repro from #52575

export interface Event<T> {
callback: (response: T) => void;
>callback : (response: T) => void
>response : T

nested: {
>nested : { nestedCallback: (response: T) => void; }

nestedCallback: (response: T) => void;
>nestedCallback : (response: T) => void
>response : T
}
}

export type CustomEvents = {
>CustomEvents : { a: Event<string>; b: Event<number>; }

a: Event<string>
>a : Event<string>

b: Event<number>
>b : Event<number>

};

declare function emit<T extends keyof CustomEvents>(type: T, data: CustomEvents[T]): void
>emit : <T extends keyof CustomEvents>(type: T, data: CustomEvents[T]) => void
>type : T
>data : CustomEvents[T]

emit('a', {
>emit('a', { callback: (r) => {}, nested: { nestedCallback: (r) => {}, },}) : void
>emit : <T extends keyof CustomEvents>(type: T, data: CustomEvents[T]) => void
>'a' : "a"
>{ callback: (r) => {}, nested: { nestedCallback: (r) => {}, },} : { callback: (r: string) => void; nested: { nestedCallback: (r: string) => void; }; }

callback: (r) => {},
>callback : (r: string) => void
>(r) => {} : (r: string) => void
>r : string

nested: {
>nested : { nestedCallback: (r: string) => void; }
>{ nestedCallback: (r) => {}, } : { nestedCallback: (r: string) => void; }

nestedCallback: (r) => {},
>nestedCallback : (r: string) => void
>(r) => {} : (r: string) => void
>r : string

},
});

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// @strict: true
// @noEmit: true

// repro from #52575

export interface Event<T> {
callback: (response: T) => void;
nested: {
nestedCallback: (response: T) => void;
}
}

export type CustomEvents = {
a: Event<string>
b: Event<number>
};

declare function emit<T extends keyof CustomEvents>(type: T, data: CustomEvents[T]): void

emit('a', {
callback: (r) => {},
nested: {
nestedCallback: (r) => {},
},
});