I am trying to convert the following to use React.memo
:
interface Props<TRowData> {
// props...
}
export function Table<TRowData>({
propA,
propB
}: Props<TRowData>) {
}
Like so (incorrect):
interface Props<TRowData> {
// props...
}
export const Table = memo<Props<TRowData>>(
({
propA,
propB
}) => {
})
How can I correct this syntax? Currently it has this error:
// Cannot find name 'TRowData'.
export const Table = memo<Props<TRowData>>(
~~~~~~~~
I am trying to convert the following to use React.memo
:
interface Props<TRowData> {
// props...
}
export function Table<TRowData>({
propA,
propB
}: Props<TRowData>) {
}
Like so (incorrect):
interface Props<TRowData> {
// props...
}
export const Table = memo<Props<TRowData>>(
({
propA,
propB
}) => {
})
How can I correct this syntax? Currently it has this error:
// Cannot find name 'TRowData'.
export const Table = memo<Props<TRowData>>(
~~~~~~~~
Share
Improve this question
asked Feb 25, 2020 at 2:17
nanobarnanobar
66.4k25 gold badges151 silver badges174 bronze badges
4 Answers
Reset to default 26I solved it by keeping the memo and non-memo separate and doing some type casting:
const TableComponent = <T,>(props: TableComponentProps<T>) => {
// ...
}
// or
function TableComponent<T>(props: TableComponentProps<T>) {
// ...
}
Then:
export const Table = memo(TableComponent) as typeof TableComponent
Or:
const typedMemo: <T>(c: T) => T = React.memo
export const Table = typedMemo(TableComponent)
With current React type declarations, it is not possible to create a generic component out of React.memo
. A solution without type assertions is to add an additional memo
function overload to leverage TS 3.4 higher order function type inference:
import React, { memo } from "react"
declare module "react" { // augment React types
function memo<A, B>(Component: (props: A) => B): (props: A) => B
// return type is same as ReturnType<ExoticComponent<any>>
}
You then will be able to make Table
component generic. Just make sure to pass a generic function to memo
:
interface Props<T> {
a: T
}
const TableWrapped = <T extends {}>(props: Props<T>) => <div>{props.a}</div>
const Table = memo(TableWrapped)
const App = () => (
<>
<Table a="foo" /> {/* (props: Props<string>) => ... */}
<Table a={3} /> {/* (props: Props<number>) => ... */}
</>
)
Playground
Don't you need to pass a component as the first parameter of React.memo
? I couldn't test it, but I feel like this is the thought process:
// Overall format:
export const Table = memo(MyComponent, MyFunction)
// With empty arrow function:
export const Table = memo(MyComponent, () => {})
// With your code:
export const Table = memo(MyComponent, ({propA, propB}: Props<TRowData>) => {
})
Simple, just pass a non-arrow function to React.memo
:
export const Table = React.memo(function<T>(props: Props<T>) {
})
or if you need default export:
export default React.memo(function Table<T>(props: Props<T>) {
})
Edit: You can check that this works with the following code:
type MyProps<T> = {someField: T};
const MyComponent = React.memo(function <T>({someField}: MyProps<T>) {
return <div>{someField}</div>
});
<MyComponent someField={222} />;
<MyComponent someField={'MYSTRING'} />;
const element = React.createElement(MyComponent, {someField: 22});
Type of element
is
React.FunctionComponentElement<{someField: number}>