diff --git a/src/services/completions.ts b/src/services/completions.ts index fbb0cf9406436..508eacee7ac37 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -5239,7 +5239,7 @@ function getCompletionData( * @returns Symbols to be suggested in an class element depending on existing memebers and symbol flags */ function filterClassMembersList(baseSymbols: readonly Symbol[], existingMembers: readonly ClassElement[], currentClassElementModifierFlags: ModifierFlags): Symbol[] { - const existingMemberNames = new Set<__String>(); + const existingMemberNames = new Set(["prototype" as __String]); // always exclude 'prototype' from completions for (const m of existingMembers) { // Ignore omitted expressions for missing members if ( @@ -5274,7 +5274,6 @@ function getCompletionData( return baseSymbols.filter(propertySymbol => !existingMemberNames.has(propertySymbol.escapedName) && - !!propertySymbol.declarations && !(getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.Private) && !(propertySymbol.valueDeclaration && isPrivateIdentifierClassElementDeclaration(propertySymbol.valueDeclaration)) ); diff --git a/tests/cases/fourslash/completionListClassMembersImplementingDynamicallyCreatedType1.ts b/tests/cases/fourslash/completionListClassMembersImplementingDynamicallyCreatedType1.ts new file mode 100644 index 0000000000000..756ed8bb500cc --- /dev/null +++ b/tests/cases/fourslash/completionListClassMembersImplementingDynamicallyCreatedType1.ts @@ -0,0 +1,34 @@ +/// + +//// type Base = { +//// [K in "foo" | "bar"]: K; +//// }; +//// +//// class Cls implements Base { /*1*/ } + +verify.completions({ + marker: "1", + includes: ["foo", "bar"], + isNewIdentifierLocation: true, +}); + +verify.completions({ + marker: "1", + includes: [ + { + name: "foo", + insertText: `foo: "foo";`, + filterText: "foo", + }, + { + name: "bar", + insertText: `bar: "bar";`, + filterText: "bar", + }, + ], + isNewIdentifierLocation: true, + preferences: { + includeCompletionsWithClassMemberSnippets: true, + includeCompletionsWithInsertText: true, + }, +}); diff --git a/tests/cases/fourslash/completionListClassMembersImplementingDynamicallyCreatedType2.ts b/tests/cases/fourslash/completionListClassMembersImplementingDynamicallyCreatedType2.ts new file mode 100644 index 0000000000000..76608fac56e85 --- /dev/null +++ b/tests/cases/fourslash/completionListClassMembersImplementingDynamicallyCreatedType2.ts @@ -0,0 +1,86 @@ +/// + +// https://github.com/microsoft/TypeScript/issues/62689 + +//// type EventType = "start" | "foo" | "bar" | "fooBar" | "end"; +//// +//// type EventDataType = T extends "fooBar" +//// ? { foo: string; bar: number } +//// : T extends "foo" +//// ? { foo: string } +//// : T extends "bar" +//// ? { bar: number } +//// : T extends EventType +//// ? Record +//// : never; +//// +//// type ListenerFunction = ( +//// context: any, +//// data: EventDataType, +//// ) => void | Promise; +//// +//// type EvtListenerMethods = { +//// [K in EventType as `on${Capitalize}`]?: ListenerFunction; +//// }; +//// +//// class A implements EvtListenerMethods { +//// onFoo(context: any, data: EventDataType<"foo">) {} +//// onBar(context: any, data: { abcd: any }) {} +//// /*1*/ +//// } +//// +//// interface EvtListener extends EvtListenerMethods {} +//// +//// class B implements EvtListener { +//// onFoo(context: any, data: EventDataType<"foo">) {} +//// onBar(context: any, data: { abcd: any }) {} +//// /*2*/ +//// } +//// +//// interface EvtListenerHardcoded { +//// onStart?: ListenerFunction<"start">; +//// onFooBar?: ListenerFunction<"fooBar">; +//// onFoo?: ListenerFunction<"foo">; +//// onBar?: ListenerFunction<"bar">; +//// onEnd?: ListenerFunction<"end">; +//// } +//// +//// class C implements EvtListenerHardcoded { +//// onFoo(context: any, data: EventDataType<"foo">) {} +//// onBar(context: any, data: { abcd: any }) {} +//// /*3*/ +//// } + +verify.completions({ + marker: ["1", "2", "3"], + includes: ["onStart", "onEnd", "onFooBar"], + excludes: ["onFoo", "onBar"], + isNewIdentifierLocation: true, +}); + +verify.completions({ + marker: ["1", "2", "3"], + includes: [ + { + name: "onStart", + insertText: `onStart?: ListenerFunction<"start">;`, + filterText: "onStart", + }, + { + name: "onEnd", + insertText: `onEnd?: ListenerFunction<"end">;`, + filterText: "onEnd", + }, + { + name: "onFooBar", + insertText: `onFooBar?: ListenerFunction<"fooBar">;`, + filterText: "onFooBar", + }, + ], + excludes: ["onFoo", "onBar"], + isNewIdentifierLocation: true, + preferences: { + includeCompletionsWithClassMemberSnippets: true, + includeCompletionsWithInsertText: true, + }, +});