Skip to content

Provide string completions for in keyword checks #60272

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

Merged
merged 2 commits into from
Feb 20, 2025
Merged
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
13 changes: 12 additions & 1 deletion src/services/stringCompletions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
addToSeen,
altDirectorySeparator,
arrayFrom,
BinaryExpression,
CallLikeExpression,
CancellationToken,
CaseClause,
Expand Down Expand Up @@ -484,7 +485,17 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL
const existing = new Set(namedImportsOrExports.elements.map(n => moduleExportNameTextEscaped(n.propertyName || n.name)));
const uniques = exports.filter(e => e.escapedName !== InternalSymbolName.Default && !existing.has(e.escapedName));
return { kind: StringLiteralCompletionKind.Properties, symbols: uniques, hasIndexSignature: false };

case SyntaxKind.BinaryExpression:
if ((parent as BinaryExpression).operatorToken.kind === SyntaxKind.InKeyword) {
const type = typeChecker.getTypeAtLocation((parent as BinaryExpression).right);
const properties = type.isUnion() ? typeChecker.getAllPossiblePropertiesOfTypes(type.types) : type.getApparentProperties();
return {
kind: StringLiteralCompletionKind.Properties,
symbols: properties.filter(prop => !prop.valueDeclaration || !isPrivateIdentifierClassElementDeclaration(prop.valueDeclaration)),
hasIndexSignature: false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that we will aggressively complete in this position? Does this need to return true if any type has a string/number index signature?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only used to return value for isNewIdentifierLocation and I don't quite understand what this is meant to represent. IIRC it, at times, works inconsistently anyway. I'd love to be able to tell what should be returned for it here but I simply just don't know ;p

};
}
return fromContextualType(ContextFlags.None);
default:
return fromContextualType() || fromContextualType(ContextFlags.None);
}
Expand Down
42 changes: 42 additions & 0 deletions tests/cases/fourslash/completionInChecks1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/// <reference path='fourslash.ts' />

// @target: esnext

//// declare const obj: {
//// a?: string;
//// b: number;
//// };
////
//// if ("/*1*/" in obj) {}
//// if (((("/*2*/"))) in obj) {}
//// if ("/*3*/" in (((obj)))) {}
//// if (((("/*4*/"))) in (((obj)))) {}
////
//// type MyUnion = { missing: true } | { result: string };
//// declare const u: MyUnion;
//// if ("/*5*/" in u) {}
////
//// class Cls1 { foo = ''; #bar = 0; }
//// declare const c1: Cls1;
//// if ("/*6*/" in c1) {}
////
//// class Cls2 { foo = ''; private bar = 0; }
//// declare const c2: Cls2;
//// if ("/*7*/" in c2) {}

verify.completions({
marker: ["1", "2", "3", "4"],
exact: ["a", "b"],
});
verify.completions({
marker: "5",
exact: ["missing", "result"],
});
verify.completions({
marker: "6",
exact: ["foo"],
});
verify.completions({
marker: "7",
exact: ["bar", "foo"],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This includes a completion from private bar = 0 but apparently that kind of a check is valid 🤷‍♂️ TS playground

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is cursed and I hate it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amen.

});