question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

renderMenuItemChildren's type is too generic

See original GitHub issue

The renderMenuItemChildren property’s type is (option: Option, ...) => JSX.Element, with Option defined as string | Record<string, any>. This means that implementors of renderMenuItemChildren need to handle both a string and a Record<string, any> (by casting onto the right type).

However, the actual type of “Option” should be inferred from the type of the options parameters.

Pull request forthcoming.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:4
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

4reactions
HarlesPiltercommented, Oct 11, 2022

This is not possible, when you use Strict in tsconfig.json. You would get an error

Type 'Option[]' is not assignable to type '{ key: string; }[]'.
  Type 'Option' is not assignable to type '{ key: string; }'.      
    Type 'string' is not assignable to type '{ key: string; }'.
2reactions
HansAarneLiblikcommented, Oct 31, 2022

What I have done to “fix” this issue is made a wrapper for Typeahead component, which I use instead of the original. Would be great if this came directly instead of doing this wrapping, but this covers our usecase now

  • Made Typeahead accept a generic
  • Added custom TypedTypes and changed component types to custom TypedTypes
  • Casting back to original types
import {ReactElement} from 'react';
import {Typeahead as SourceTypeahead} from 'react-bootstrap-typeahead';
import {TypeaheadComponentProps} from 'react-bootstrap-typeahead/types/components/Typeahead';
import {RenderMenuItemChildren, TypeaheadMenuProps} from 'react-bootstrap-typeahead/types/components/TypeaheadMenu';
import {
  FilterByCallback,
  LabelKey,
  RenderToken,
  RenderTokenProps,
  TypeaheadPropsAndState,
} from 'react-bootstrap-typeahead/types/types';

type TypedTypeaheadProps<T extends Option> = Omit<
  TypeaheadComponentProps,
  'filterBy' | 'renderMenuItemChildren' | 'renderToken' | 'labelKey' | 'onChange' | 'options'
> & {
  filterBy?: string[] | TypedFilterByCallback<T>;
  renderMenuItemChildren?: TypedRenderMenuItemChildren<T>;
  renderToken?: TypedRenderToken<T>;
  labelKey?: TypedLabelKey<T>;
  onChange?: TypedOnChange<T>;
  options: T[]
};

export const Typeahead = <T extends Option = never>(props: TypedTypeaheadProps<T>): ReactElement => {
  return (
    <SourceTypeahead
      {...props}
      filterBy={props.filterBy as string[] | FilterByCallback}
      renderMenuItemChildren={props.renderMenuItemChildren as RenderMenuItemChildren}
      renderToken={props.renderToken as RenderToken}
      labelKey={props.labelKey as LabelKey}
      onChange={props.onChange as (selected: Option[]) => void}
    />
  );
};

// Importing from Typeahead messed up TS
type Option = string | Record<string, any>;
// The following wrappers are added to support generics in our callbacks. We're casting back to original later on
export type TypedLabelKey<T extends Option> = T extends object ? (string & keyof T) | ((option: T) => string) : never;
type TypedOnChange<T extends Option> = (selected: T[]) => void;
type TypedRenderToken<T extends Option> = (option: T, props: RenderTokenProps, idx: number) => JSX.Element;
type TypedFilterByCallback<T extends Option> = (option: T, state: TypeaheadPropsAndState) => boolean;
type TypedRenderMenuItemChildren<T extends Option> = (
  option: T,
  menuProps: TypeaheadMenuProps,
  idx: number
) => JSX.Element;

This way I can use Typeahead as follows

import {Typeahead} from 'app/core/elements/TypedTypeahead';

type MyType = {
  id: number;
  name: string;
  values: string[];
};

export const MyComp = () => {
  return (
    <Typeahead<MyType>
      options={[]}
      renderMenuItemChildren={(item, menuProps) => <div />}
      filterBy={['name']}
      onChange={(selected) => {}}
    />
  );
};

and as you can see, IDE knows about the types correctly image

Read more comments on GitHub >

github_iconTop Results From Across the Web

Developers - renderMenuItemChildren's type is too generic -
renderMenuItemChildren's type is too generic. ... The renderMenuItemChildren property's type is (option: Option, ...) => JSX.Element , with Option defined ...
Read more >
react-bootstrap-typeahead TypeScript- Ref - getInstance does ...
As you saw, the Typeahead class is itself generic, but the generic type doesn't matter for what you are trying to do, so...
Read more >
Incident Response - Hybrid Analysis
... type "Composite Document File V2 Document Cannot read section info" "9f5df6b0f1a4b9a60d0074c369314e1a_1_.js" has type "ASCII text with very long lines"
Read more >
Java Generics FAQs - Generic And Parameterized Types
In addition to concrete instantiation there so-called wildcard instantiations . They do not have concrete types as type arguments, but so-called ...
Read more >
[Solved]-React redux instantiate non-component class-Reactjs
Type 'null' is not assignable to type 'SetStateAction<string>' · Trying to add a live website URL in ReactJs · 'this' undefined in renderMenuItemChildren...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found