Microsoft/TypeScript

Auto-completion fails when key type is aliased

Open

#47,944 opened on Feb 18, 2022

View on GitHub
 (1 comment) (5 reactions) (0 assignees)TypeScript (6,726 forks)batch import
Domain: LS: Completion ListsExperience EnhancementHelp WantedSuggestion

Repository metrics

Stars
 (48,455 stars)
PR merge metrics
 (Avg merge 6d 17h) (9 merged PRs in 30d)

Description

Bug Report

🔎 Search Terms

autocomplete, autocompletion, generic, keyof

🕗 Version & Regression Information

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

⏯ Playground Link

Playground link with relevant code

💻 Code

// Disallows any properties in TActual that are not in T
type Exactly<T, TActual> = T & Record<Exclude<keyof TActual, keyof T>, never>;

type DwarfName = 'Doc' | 'Grumpy' | 'Happy' | 'Sleepy' | 'Bashful' | 'Sneezy' | 'Dopey';

// ⛔️ Auto-completion for dwarf names doesn't work
declare function passthroughDwarfAges1<
  TAges extends Exactly<{ [key in DwarfName]?: number }, TAges>
  //                              ^^^^^^^^^
  //                              This is the only difference between the declarations
>(ages: TAges): TAges;

// ✅ Auto-completion works
interface DwarfNameMap {
  Doc: any; Grumpy: any; Happy: any; Sleepy: any; Bashful: any; Sneezy: any; Dopey: any;
}
declare function passthroughDwarfAges2<
  TAges extends Exactly<{ [key in keyof DwarfNameMap]?: number }, TAges>
  //                              ^^^^^^^^^^^^^^^^^^
>(ages: TAges): TAges;

// ⛔️ But it doesn't work if we extract "keyof DwarfNameMap" into a type
type DwarfNameMapKey = keyof DwarfNameMap;
declare function passthroughDwarfAges3<
  TAges extends Exactly<{ [key in DwarfNameMapKey]?: number }, TAges>
  //                              ^^^^^^^^^^^^^^^
>(ages: TAges): TAges;

// ⛔️ It also doesn't work with a non-interface type
type DwarfNameMapType = Record<keyof DwarfNameMap, void>;
declare function passthroughDwarfAges4<
  TAges extends Exactly<{ [key in keyof DwarfNameMapType]?: number }, TAges>
  //                              ^^^^^^^^^^^^^^^^^^^^^^
>(ages: TAges): TAges;

🙁 Actual behavior

This code snippet contains four almost identical declarations for a function passthroughDwarfAges, which is meant to be called like this: passthroughDwarfAges({ Doc: 64, Happy: 58 }). The only difference is the exact syntax for the type of the key.

While typing dwarf names, I get auto-completion on declaration 2, but not on 1, 3, or 4.

🙂 Expected behavior

Declarations 3 and 4 are virtually identical to declaration 2. The only difference is that declaration 3 extracts keyof DwarfNameMap into a named type, while declaration 4 uses a type instead of an interface for DwarfNameMap. Given that declaration 2 gives auto-completion, I'd have expected declarations 3 and 4 to auto-complete, too.

And I'd have hoped that the very similar but much more idiomatic declaration 1 should work, too. 🙂

Contributor guide