{"record":{"id":"2c7a2f8341216f23","repo":"angular/components","slug":"keymanager-items-in-typeahead-mode-must-implement","errorCode":null,"errorMessage":"KeyManager items in typeahead mode must implement the `getLabel` method.","messagePattern":"KeyManager items in typeahead mode must implement the `getLabel` method\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cdk/a11y/key-manager/typeahead.ts","lineNumber":56,"sourceCode":"  private readonly _selectedItem = new Subject<T>();\n  readonly selectedItem: Observable<T> = this._selectedItem;\n\n  constructor(initialItems: readonly T[], config?: TypeaheadConfig<T>) {\n    const typeAheadInterval =\n      typeof config?.debounceInterval === 'number'\n        ? config.debounceInterval\n        : DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL_MS;\n\n    if (config?.skipPredicate) {\n      this._skipPredicateFn = config.skipPredicate;\n    }\n\n    if (\n      (typeof ngDevMode === 'undefined' || ngDevMode) &&\n      initialItems.length &&\n      initialItems.some(item => typeof item.getLabel !== 'function')\n    ) {\n      throw new Error('KeyManager items in typeahead mode must implement the `getLabel` method.');\n    }\n\n    this.setItems(initialItems);\n    this._setupKeyHandler(typeAheadInterval);\n  }\n\n  destroy() {\n    this._pressedLetters = [];\n    this._letterKeyStream.complete();\n    this._selectedItem.complete();\n  }\n\n  setCurrentSelectedItemIndex(index: number) {\n    this._selectedItemIndex = index;\n  }\n\n  setItems(items: readonly T[]) {\n    this._items = items;","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/cdk/a11y/key-manager/typeahead.ts#L38-L74","documentation":"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.","triggerScenarios":"Constructing ListKeyManager with withTypeAhead() where items are objects/classes that don't implement getLabel(), and at least one item exists at construction time.","commonSituations":"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`.","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."],"exampleFix":"// before\nitems = [{id: 1, name: 'Foo'}];\nnew ListKeyManager(items as any).withTypeAhead();\n// after\ninterface Item { getLabel(): string; }\nitems: Item[] = [{id: 1, name: 'Foo', getLabel() { return this.name; }}];\nnew ListKeyManager(items).withTypeAhead();","handlingStrategy":"type-guard","validationCode":"const usable = initialItems.every((i: any) => typeof i.getLabel === 'function');\nif (!usable) throw new Error('All key manager items must implement getLabel');","typeGuard":"function hasGetLabel(item: unknown): item is {getLabel(): string} {\n  return typeof item === 'object' && item !== null &&\n    typeof (item as {getLabel?: unknown}).getLabel === 'function';\n}","tryCatchPattern":"try {\n  manager = new ListKeyManager(items).withTypeAhead();\n} catch (e) {\n  if ((e as Error).message.includes('getLabel')) {\n    manager = new ListKeyManager(items.map(withDefaultLabel)).withTypeAhead();\n  } else throw e;\n}","preventionTips":["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."],"tags":["angular","cdk","a11y","list-key-manager","typeahead"],"backgroundTag":"missing-required-method","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}