angular/components · error · Error
KeyManager items in typeahead mode must implement the `getLa
Error message
KeyManager items in typeahead mode must implement the `getLabel` method.
What it means
When ListKeyManager typeahead mode is enabled, the manager needs each item's label to match typed keystrokes. The typeahead implementation validates in dev mode that every item implements getLabel(); if any item lacks it, the constructor throws.
Source
Thrown at src/cdk/a11y/key-manager/typeahead.ts:56
private readonly _selectedItem = new Subject<T>();
readonly selectedItem: Observable<T> = this._selectedItem;
constructor(initialItems: readonly T[], config?: TypeaheadConfig<T>) {
const typeAheadInterval =
typeof config?.debounceInterval === 'number'
? config.debounceInterval
: DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL_MS;
if (config?.skipPredicate) {
this._skipPredicateFn = config.skipPredicate;
}
if (
(typeof ngDevMode === 'undefined' || ngDevMode) &&
initialItems.length &&
initialItems.some(item => typeof item.getLabel !== 'function')
) {
throw new Error('KeyManager items in typeahead mode must implement the `getLabel` method.');
}
this.setItems(initialItems);
this._setupKeyHandler(typeAheadInterval);
}
destroy() {
this._pressedLetters = [];
this._letterKeyStream.complete();
this._selectedItem.complete();
}
setCurrentSelectedItemIndex(index: number) {
this._selectedItemIndex = index;
}
setItems(items: readonly T[]) {
this._items = items;View on GitHub (pinned to 0411926e7d)
Solutions
- Implement getLabel(): string on every item type passed to ListKeyManager.
- Use a proper interface (e.g. interface ListItem { getLabel(): string; disabled?: boolean }) so TypeScript enforces it.
- If typeahead isn't needed, remove withTypeAhead() from the config.
- If items are added later, note the check runs on initial items — still implement getLabel to avoid runtime failures on navigation.
Example fix
// before
items = [{id: 1, name: 'Foo'}];
new ListKeyManager(items as any).withTypeAhead();
// after
interface Item { getLabel(): string; }
items: Item[] = [{id: 1, name: 'Foo', getLabel() { return this.name; }}];
new ListKeyManager(items).withTypeAhead(); Defensive patterns
Strategy: type-guard
Validate before calling
const usable = initialItems.every((i: any) => typeof i.getLabel === 'function');
if (!usable) throw new Error('All key manager items must implement getLabel'); Type guard
function hasGetLabel(item: unknown): item is {getLabel(): string} {
return typeof item === 'object' && item !== null &&
typeof (item as {getLabel?: unknown}).getLabel === 'function';
} Try / catch
try {
manager = new ListKeyManager(items).withTypeAhead();
} catch (e) {
if ((e as Error).message.includes('getLabel')) {
manager = new ListKeyManager(items.map(withDefaultLabel)).withTypeAhead();
} else throw e;
} Prevention
- Define a shared interface with getLabel(): string for all item types used with typeahead.
- Avoid `as any` casts when passing items to ListKeyManager.
- Skip withTypeAhead() when items have no labels.
When it happens
Trigger: Constructing ListKeyManager with withTypeAhead() where items are objects/classes that don't implement getLabel(), and at least one item exists at construction time.
Common situations: Switching items from strings (which typeahead can't label either) or from DOM elements to plain objects without adding getLabel; custom item types after refactoring; passing a signal/QueryList of untyped items where TS structural checks were bypassed with `as any`.
Related errors
- ListKeyManager constructed with a signal must receive an inj
- ListKeyManager items in typeahead mode must implement the `g
- CdkDropList could not find an element container matching the
- Invalid DOM structure for drop list. Alternate container ele
- Invalid DOM structure for drop list. All items must be place
AI-assisted analysis of angular/components@0411926e7d (2026-08-31).
Data as JSON: /api/errors/2c7a2f8341216f23.
Report an issue: GitHub.