angular/components · error · Error

ListKeyManager items in typeahead mode must implement the `g

Error message

ListKeyManager items in typeahead mode must implement the `getLabel` method.

What it means

ListKeyManager.withTypeAhead needs to read the text label of each item to match keystrokes; therefore every item in the QueryList must implement getLabel(): string. withTypeAhead throws this dev-mode error if any item lacks a getLabel function (when the list is non-empty).

Source

Thrown at src/cdk/a11y/key-manager/list-key-manager.ts:148

  /**
   * Modifier keys which are allowed to be held down and whose default actions will be prevented
   * as the user is pressing the arrow keys. Defaults to not allowing any modifier keys.
   */
  withAllowedModifierKeys(keys: ListKeyManagerModifierKey[]): this {
    this._allowedModifierKeys = keys;
    return this;
  }

  /**
   * Turns on typeahead mode which allows users to set the active item by typing.
   * @param debounceInterval Time to wait after the last keystroke before setting the active item.
   */
  withTypeAhead(debounceInterval: number = 200): this {
    if (typeof ngDevMode === 'undefined' || ngDevMode) {
      const items = this._getItemsArray();
      if (items.length > 0 && items.some(item => typeof item.getLabel !== 'function')) {
        throw Error('ListKeyManager items in typeahead mode must implement the `getLabel` method.');
      }
    }

    this._typeaheadSubscription.unsubscribe();

    const items = this._getItemsArray();
    this._typeahead = new Typeahead(items, {
      debounceInterval: typeof debounceInterval === 'number' ? debounceInterval : undefined,
      skipPredicate: item => this._skipPredicateFn(item),
    });

    this._typeaheadSubscription = this._typeahead.selectedItem.subscribe(item => {
      this.setActiveItem(item);
    });

    return this;
  }

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Implement getLabel(): string on every item directive/component managed by the key manager.
  2. Create a shared interface (e.g., interface WithLabel { getLabel(): string }) and have all items implement it.
  3. Remove withTypeAhead() if keyboard typeahead is not needed.

Example fix

// before
export class MyOption { constructor(public value: string) {} }

// after
export class MyOption { constructor(public value: string) {} }
getLabel(): string { return this.value; }
Defensive patterns

Strategy: type-guard

Validate before calling

interface LabelItem { getLabel(): string; }
function allItemsHaveLabel(items: unknown[]): items is LabelItem[] {
  return items.every(i => typeof (i as LabelItem).getLabel === 'function');
}
if (allItemsHaveLabel(options.toArray())) keyManager.withTypeAhead();

Type guard

function implementsGetLabel(item: unknown): item is { getLabel(): string } {
  return typeof (item as { getLabel?: unknown }).getLabel === 'function';
}

Try / catch

try {
  keyManager.withTypeAhead();
} catch (e) {
  if ((e as Error).message.includes('getLabel')) {
    console.error('Items must implement getLabel for typeahead');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling keyManager.withTypeAhead() where the managed QueryList contains directive/component instances that do not define getLabel(); adding a new item type to the list that was not updated for typeahead; passing a generic ListKeyManager over plain objects.

Common situations: Mixing item classes in a listbox/menu; upgrading CDK and enabling typeahead on an existing key manager; implementing a custom option directive modeled after an older API without getLabel.

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/5d8174ba35ba5cbc. Report an issue: GitHub.