Skip to content

Autocompletion fails - unnecessarily narrow for inferred Generic #52726

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
cefn opened this issue Feb 12, 2023 · 1 comment
Open

Autocompletion fails - unnecessarily narrow for inferred Generic #52726

cefn opened this issue Feb 12, 2023 · 1 comment
Labels
Domain: Completion Lists The issue relates to showing completion lists in an editor Experience Enhancement Noncontroversial enhancements Help Wanted You can do this Suggestion An idea for TypeScript
Milestone

Comments

@cefn
Copy link

cefn commented Feb 12, 2023

Bug Report

In the following example typescript IS able to judge the set of valid strings, (as shown by the compiler error), but somehow autocompletion from the language server CAN'T resolve that set. It resolves instead to the set of strings already populated, as shown below in screenshots from the typescript playground

image

image

image

Ideally this approach should have editor autocompletion support constraining strings to type Role, NOT type Evidenced. The type Evidenced is actually inferred from the items being edited right now so the programmer should be able to draw from the broader set Role.

🔎 Search Terms

Autocompletion, inferred, generic, constraint, "too narrow"

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about inference

⏯ Playground Link

Playground link with relevant code

💻 Code

const ROLES = ["artist", "baker", "candlestickmaker"] as const satisfies ReadonlyArray<string>;
type Role = typeof ROLES[number];

function tag<Evidenced extends Role>(
  fn: (evidence: (role: Evidenced) => void) => void,
  ...roles: [Evidenced, ...Evidenced[]]
) {
  // decorate fn
  return () => {;};
}

const decoratedFn = tag(
  () => {;},
  "artist", "baker", "candle"
)

🙁 Actual behavior

The set of strings for autocompletion is initially empty, when it should be populated by Role. After one or more entries have been provided to the list, it then autocompletes only to strings which are already provided.

🙂 Expected behavior

The set of strings for autocompletion of the arguments to the tag function should be populated by Role

Background

The motivating example is within a portfolio of narrative content (interactive fiction-style) using Generator functions. This wrapper function defines a composition function type to evidence roles either by invoking the callback between yields (when a yielded narrative references that role), or if that hasn't happened by calling the callback for those roles when the function eventually returns (allowing very terse definitions for simple narratives without requiring inline callbacks).

This ensures that not referencing at least one role is an error, and offers the delight that narrative elements which touch on some role can lead to an immediate update of the displayed model (showing which roles have been evidenced).

The central purpose of this typing is to assist with editor support, so not being able to have autocompletion is a real dead-end.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Help Wanted You can do this Domain: Completion Lists The issue relates to showing completion lists in an editor Experience Enhancement Noncontroversial enhancements labels Feb 17, 2023
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Feb 17, 2023
@cefn
Copy link
Author

cefn commented Feb 25, 2023

Thanks @RyanCavanaugh for the vote of confidence that this might be an enhancement.

The original example included motivating context (a sketch of a function decorator, which would actually consume the narrowed inferred type).

However, an even simpler illustration to demonstrate the problem is below, where autocompletion of the last argument to narrowFn draws from the already-inferred Narrow when it should draw from Wide.

Unless the Narrow Generic is explicit, the argument list actually drives the inference, rather than following it. Autocompletion should therefore support extending the list that drives Narrow with other candidates from Wide.

type Wide = "artist" | "baker" | "candlestickmaker";

function narrowingFn<Narrow extends Wide>(
  ...roles: [Narrow, ...Narrow[]]
) {
 }

narrowingFn(
  // a cursor at the end of `candle` fails to autocomplete to `candlestickmaker` 
  "artist", "baker", "candle"
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Domain: Completion Lists The issue relates to showing completion lists in an editor Experience Enhancement Noncontroversial enhancements Help Wanted You can do this Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

2 participants