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.

There are missing props in the TypeScript type declaration file for ListItem, and also these types should ideally be generics.

  • I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior

It should be possible to use the ContainerComponent and ContainerProps props of the ListItem component from TypeScript. Also, I expected that ListItem and MenuItem would be generic types to account for the fact that any additional props are passed to the component specified by the component prop, but they’re not. To be specific, in this file, the interface is currently defined like this:

export interface MenuListProps ...

whereas I would have expected to see something like this:

export interface MenuListProps<TContainerComponentProps = {}> ...

Current Behavior

This TypeScript (.tsx) code does not compile:

<ListItem ContainerComponent="div" ContainerProps={{className: 'demo'}}>an item</ListItem>

Steps to Reproduce (for bugs)

Create the following test component in TypeScript:

import React from 'react'
import { ListItem, ListItemProps } from 'material-ui/List'

const Test: React.SFC<{}> = () => {
    return <ListItem ContainerComponent="div" ContainerProps={{className: 'demo'}}>an item</ListItem>
}
export default Test

Notes

The priority here is adding ContainerComponent and ContainerProps to the type declaration. Making it generic (e.g. MenuListProps<TContainerComponentProps = {}>) is arguably a best practice and would be nice, but might not be so practically useful in this case. If it were a class component it might be more helpful, but as far as I can tell, TypeScript does not provide a way to alias generic functions that would be any more concise than my current solution of using a typecast:

const MyMenuItem = MenuItem as React.ComponentType<MenuItemProps & MyComponentProps>
...
    render() {
        return <MyMenuItem component={MyComponent} somePropToMyComponent="demo">an item</MyMenuItem>
    }

Your Environment

Tech Version
Material-UI 1.0.0-beta.32
React 16.2.0
browser Chrome 64
TypeScript 2.7.1

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:27 (19 by maintainers)

github_iconTop GitHub Comments

2reactions
pelotomcommented, Mar 3, 2018

Maybe my suggestion of using a generic for the component prop would work for the ContainerComponent and ContainerProps props too

For generic props to be useful you also need generic components, and unfortunately those aren’t well supported currently; see https://github.com/Microsoft/TypeScript/issues/6395.

I think this is fine, albeit not as type safe as one could hope:

ContainerComponent?: React.ReactType<React.HTMLAttributes<any>>;
ContainerProps?: React.HTMLAttributes<any>;

@oliviertassinari as a larger design note, the FooComponent/FooProps pattern that’s common in Material UI presents a tricky problem for making type safe. It would be much easier and more powerful if we just used render props for these situations, e.g.

renderContainer?: (props: { className: string; children: ReactNode }) => ReactNode

Here you can be very specific about the props ({ className: string; children: ReactNode }) because you know that’s exactly what will be passed, and it’s up to the provider of the render prop to render that however they see fit. They can use whatever root element they want, whatever attributes they want, and even add more children. It allows complete customization while remaining perfectly type safe.

1reaction
pelotomcommented, Mar 4, 2018
const C = ({ className, children }) =>
    <Bar className={className} someAdditionalFlag />
      {children}
    </Bar>
 
<Foo ContainerComponent={C}>
  ...
</Foo>

If you just extract it to a variable in the render method, you haven’t saved anything; it will still be a new component on every render. And if someAdditionalFlag is something that had to be computed from the props, you can’t define C at the module level. You’re forced to make your component into a class if it wasn’t already, with C a field on it (see example above).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Render Props - React
The term “render prop” refers to a technique for sharing code between React components using a prop whose value is a function. A...
Read more >
React Render Props - Share code between components
As mentioned in the react docs: The term “render prop” refers to a technique for sharing code between React components using a prop...
Read more >
Use a Render Prop! - Medium
A render prop is a function prop that a component uses to know what to render. More generally speaking, the idea is this:...
Read more >
React Reference Guide: Render props - LogRocket Blog
An all-in-one reference guide on render props in React, including how to implement render props, how to implement HOCs, and more.
Read more >
React.js Render Props - GeeksforGeeks
The Render Props is a technique in ReactJS for sharing code between React components using a prop whose value is a function.
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