Skip to content

Completions from template literal types #59794

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

MichalMarsalek
Copy link
Contributor

@MichalMarsalek MichalMarsalek commented Aug 29, 2024

Implements completions from types of the form

type T = `a${string}b${string}c...y${string}z`

, that is, from template literal types where string is the only placeholder. For the other cases (prefix${number}), it's much less clear to me how they should work.

The completions implemented in this PR suggest appending the "next" (the first that is not already included) text part of the template literal type. For example

const x: T = "a_/**/

suggests a_b.

Closes #59698

Please verify that:

  • There is an associated issue in the Backlog milestone (required)
  • Code is up-to-date with the main branch
  • You've successfully run hereby runtests locally
  • There are new or updated unit tests validating the change

@typescript-bot typescript-bot added the For Backlog Bug PRs that fix a backlog bug label Aug 29, 2024
@@ -297,6 +310,22 @@ function convertStringLiteralCompletions(
}
}

function getStringLiteralCompletionFromTemplateLiteralTypeAndTextOfNode(type: TemplateLiteralType, tokenTextContent: string, quoteChar: CharacterCodes.backtick | CharacterCodes.singleQuote | CharacterCodes.doubleQuote) {
Copy link
Contributor

Choose a reason for hiding this comment

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

There is an existing algorithm for matching strings against template literal types that you can find in isTypeMatchedByTemplateLiteralType. Instead of trying to implement a custom one, I'd recommend looking into how you could reuse that one. You can expose some checker functionality on the TypeChecker using new methods annotated with /** @internal */.

Perhaps you will have to focus on the algorithm in inferFromLiteralPartsToTemplateLiteral. It could return a number for the last segment matched successfully instead of undefined. Using this number you could look at the text after it and suggest that as autocompletion.

Note that this is just a rough idea, I don't know how feasible it will be in practice 😉

It could be nice to use the same algorithm to autocomplete properties coming from index signatures with template literal keys. You don't have to implement this as part of this PR though. One thing at a time 😅

Copy link
Contributor Author

@MichalMarsalek MichalMarsalek Aug 29, 2024

Choose a reason for hiding this comment

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

Hmm, this matching works in the escaped string (source code) space, while the checker's works in raw string content space. Shouldn't be the biggest issue though, instead of escaping the type.text, we would need to unescape token.content. Especially for future generalisations, this is probably a good direction to take but this version is so simple, that I didn't feel the need to use the checker.

Copy link
Contributor Author

@MichalMarsalek MichalMarsalek Aug 29, 2024

Choose a reason for hiding this comment

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

Also, inferFromLiteralPartsToTemplateLiteral starts by first checking that both the starts and the ends of the source and the target are compatible, which is not what we need here. (Ok but that seems to be just for a perf reason? and could be skipped with a flag.)

Copy link
Contributor Author

@MichalMarsalek MichalMarsalek Aug 29, 2024

Choose a reason for hiding this comment

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

Actually, I don't think that function is very useful for matching of the partial string. I think that this requires a different algorithm by nature.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could u expand on that? At the very least the rules there could guide u how to handle number interpolations and more

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, there are functions like isValidTypeForTemplateLiteralPlaceholder that could certainly prove usefule, but I'm not sure the overall algorithm that finds the target text parts in the source type is that reuseable. And

it's much less clear to me how they should work

meant less "I don't know how to do it" and more "I don't know what it should be doing". Like in

const x: `a${number}` = "a/**/

what is the completion? I guess nothing? How about

const x: `a${number}` = "ab/**/

Maybe replacement of "ab with "a ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
Status: Not started
Development

Successfully merging this pull request may close these issues.

Suboptimal completion list for template literal type member
3 participants