Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metadata type not inferred from supplied data. #205

Open
airtonix opened this issue Dec 23, 2024 · 1 comment
Open

Metadata type not inferred from supplied data. #205

airtonix opened this issue Dec 23, 2024 · 1 comment

Comments

@airtonix
Copy link

Describe the bug

Despite #193 claiming it fixed this issue, installing 2.10.0 reveals that:

  • <TreeView<CustomMetaDataType> /> is not possible
  • <TreeView data={myFlatListOfTypedItems} nodeRenderer={(element) => (...)} /> doesn't infer the type from my items and enforces the default type for metadata.

the index.d.ts has this at the bottom:

declare const TreeView: React.ForwardRefExoticComponent<ITreeViewProps<IFlatMetadata> & React.RefAttributes<HTMLUListElement>>;
export default TreeView;

Which basically just decides it doesn't care what kind of pizza you ordered, you're getting a Margherita.

Screencast.from.2024-12-23.19-13-30.mp4

Where my TocLeaf looks like

type TocLeaf = Omit<INode<{ href: string }>, 'id'> & { id: string };

Code That Causes The Issue

When using forward ref and expecting to allow others to utilise the generic type parameter, you need to do two things:

  1. Not define the component inline with the forwardRef function, instead define it outside with two parameters: props, and ref
  2. use this defined function reference in an exported implementation of forwardRef that is typecast with the return value of function in 1.:
export interface ComponentRef {
  foo: VoidFunction;
}

export type ComponentProps<T> = {
  data: T[];
  onSomething: (data: T) => void;
};

const Component = <T,>(props: ComponentProps<T>, ref: Ref<ComponentRef>) => {
  const foo = useCallback(() => {
    console.log(props.data);
  }, [props]);

  useImperativeHandle(ref, () => ({
    foo,
  }));

  return <div>{props.data.length}</div>;
};

const WithForwardedGeneric = forwardRef(Component) as <T>(
  props: ComponentProps<T> & { ref?: Ref<ComponentRef> }
) => ReturnType<typeof Component>;

export const Foo = () => {
  return (
    <WithForwardedGeneric<{ yes: false }>
      data={[]}
      onSomething={(data) => console.log(data)}
    />
  );
};

image

So to put this in context:

export interface TreeviewComponentRef {
  foo: VoidFunction;
}

// existing types for tree view props. no change needed
export type ITreeViewProps<M extends IFlatMetadata = IFlatMetadata> = { ... }

// 1. define component outside of forwardRef
const TreeViewComponent = <T,>(props: ITreeViewProps<T>, ref: Ref<TreeviewComponentRef>) => {...};

// 2. export the forwardRef, with an enforced type generic and return type.
const TreeView = forwardRef(TreeViewComponent) as <T>(
  props: ITreeViewProps<T> & { ref?: Ref<TreeviewComponentRef> }
) => ReturnType<typeof TreeViewComponent>;

// example using it.
export const MyAmazingApp = () => {
  return (
    <TreeView<{ yes: false }>
      data={[]}
      nodeRenderer={(element) => console.log(data.metadata.yes === false)}
    />
  );
};

However, I'm not smart enough to work out how to make this work with your use of propTypes (i haven't used that concept for nearly 6 years now)

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

@dgreene1
Copy link
Owner

Thanks for the detailed report. The team and I are on vacation for at least a week. But they’ll look at it when we get back.

If you are willing to make a PR, that will speed things up.

cc @mellis481 @yhy-1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants