Use generics in React to make dynamic and flexible components
You might be used to using generics with functions but you can also use them with react components.
So here this Table
component takes in an array of items which I've currently typed as just id: string
and then it also takes a function to render the item which says item: {id: string}
interface TableProps { items: { id: string }[] renderItem: (item: { id: string }) => React.ReactNode}export const Table = (props: TableProps) => { return null}
What you want here is to be able to pass in any items and for that id
string to then propagate through to the renderItem
. You might try the following, using TItem
, but this actually isn't valid.
export const Table = <TItem>(props: TableProps) => { return null}
What you need to do instead is you need to turn this Table
into a standard function
.
export function Table<TItem>(props: TableProps) { return null}
We need to make TableProps
generic as well with TItem
. Remember to use TItem
in the items
array and the renderItem
function.
interface TableProps<TItem> { items: TItem[] renderItem: (item: TItem) => React.ReactNode}export function Table<TItem>(props: TableProps<TItem>) { return null}
And now anything we put in the Component
props items
will be propagated through to our item
because it's generic.
If we ever want to pass the generic manually we specificy it with our Table
instance. Now the example below will error out since id
should be a number not a string.
const Component = () => { return ( <Table<{ id: number }> items={[{ id: "1", name: "Matt" }]} renderItem={(item) => <div>{item.id}</div>} ></Table> )}
So it's a funny syntax and not a lot of people know about it. I kind of stumbled on it by accident and every time. But, every time I use it I think, "wow that's pretty cool!"
Transcript
0:00 You might be used to using generics with functions, but you can also use them with React components. Here, this Table component, it takes in an array of items, which have currently time to just ID String. Then it also takes a function to render the item, which says Item ID String.
0:16 Actually, what you want here is you want to be able to parse in any items. For that ID String to then propagate through to the renderItem here. We can do that. You can make a item here, which would be, lets say, tItem. You might be put off by the fact that inside this TSX file, this syntax actually isn't valid.
0:36 What you need to do instead is you need to turn this table into a function, which looks like this, and remove the arrow. Now, you're allowed to use it. Here, we probably need to make this generic as well, tItem. Let's add tItem up here.
0:51 We can take the ID String and just put tItem in there. Anything we put into here, name, Matt, for instance, will be propagated through to our item because it's generic. If we ever want to pass the generic manually and specify it, then we can pass it here. We can say, "ID equals a number," for instance.
1:10 This will array because it's not passing that. It's a funny syntax. Not a lot of people know about it. I stumbled on it by accident. Every time I use it, I think, "Wow, that's pretty cool."
You can use generics in React to make incredibly dynamic, flexible components. Here, I make a Table component with a generic 'items' type.
More Tips
Type Predicates
1 min
TypeScript 5.1 Beta is OUT!
2 mins
How to Name your Types
4 mins
Don't use return types, unless...
4 mins
TypeScript 5.0 Beta Deep Dive
6 mins
Conform a Derived Type Without Losing Its Literal Values
1 min
Avoid unexpected behavior of React’s useState
1 min
Understand assignability in TypeScript
2 mins
Compare function overloads and generics
1 min
Use infer in combination with string literals to manipulate keys of objects
1 min
Access deeper parts of objects and arrays
1 min
Ensure that all call sites must be given value
1 min
Understand how TypeScript infers literal types
1 min
Get a TypeScript package ready for release to NPM in under 2 minutes
1 min
Use assertion functions inside classes
1 min
Assign local variables to default generic slots to dry up your code and improve performance
2 mins
Know when to use generics
2 mins
Map over a union type
1 min
Make accessing objects safer by enabling 'noUncheckedIndexedAccess' in tsconfig
1 min
Use generics to dynamically specify the number, and type, of arguments to functions
1 min
Use 'declare global' to allow types to cross module boundaries
2 mins
Turn a module into a type
2 mins
Create autocomplete helper which allows for arbitrary values
2 mins
Use deep partials to help with mocking an entity
1 min
Throw detailed error messages for type checks
1 min
Create a 'key remover' function which can process any generic object
1 min
Create your own 'objectKeys' function using generics and the 'keyof' operator
1 min
Write your own 'PropsFrom' helper to extract props from any React component
1 min
Use 'extends' keyword to narrow the value of a generic
1 min
Use function overloads and generics to type a compose function
2 mins
Decode URL search params at the type level with ts-toolbelt
2 mins
Use 'in' operator to transform a union to another union
2 mins
Derive a union type from an object
2 mins