Provided you have installed @types/react and @types/react-dom you will have most react types already defined.
For Function Components there is the type FunctionComponent or FC for short. It is also generic so you can specify the props type.
import type { FC } from 'react';
const A: FC<{ a: number }> = ({ a }) => <>{a}</>;
const B: FC<{ b: number }> = ({ b }) => <>{b}</>;
type Data = {
[id: string]: FC<any>;
};
const data: Data = {
aa: A,
bb: B,
};
const Usage = () => (
<>
A: {data.aa({ a: 12 })}
B: {data.bb({ b: 'hi' })}
</>
);
demo: https://stackblitz.com/edit/react-ts-y9ejme?file=App.tsx
Note however you lose the props type by typing an object as Data, because you're allowing any props types. Typescript will not see that b is supposed to be a number, not a string. It would be better to exclude that type and just let typescript infer the type from the object literal.
const A: FC<{ a: number }> = ({ a }) => <>{a}</>;
const B: FC<{ b: number }> = ({ b }) => <>{b}</>;
const data = {
aa: A,
bb: B,
};
export default function App() {
return (
<>
A: {data.aa({ a: 12 })}
{/* Error: Type 'string' is not assignable to type 'number'. */}
B: {data.bb({ b: 'hi' })}
</>
);
}
demo: https://stackblitz.com/edit/react-ts-j8uagi?file=App.tsx
Otherwise, you'll have to explicitly type the properties:
const A: FC<{ a: number }> = ({ a }) => <>{a}</>;
const B: FC<{ b: number }> = ({ b }) => <>{b}</>;
type Data = {
aa: typeof A;
bb: typeof B;
};
const data: Data = {
aa: A,
bb: B,
};
export default function App() {
return (
<>
A: {data.aa({ a: 12 })}
{/* Error: Type 'string' is not assignable to type 'number'. */}
B: {data.bb({ b: 'hi' })}
</>
);
}
demo: https://stackblitz.com/edit/react-ts-ykbq8q?file=App.tsx
Or ensure that the properties you are accessing are common for all components:
const A: FC<{ a: number }> = ({ a }) => <>I'm an A {a}</>;
const B: FC<{ a: number, b: number }> = ({ a, b }) => <>I'm a B {a}</>;
type Data = {
[id: string]: FC<{ a: number }>;
};
const data: Data = {
aa: A,
bb: B,
};
export default function App() {
return (
<>
A: {data.aa({ a: 12 })}
{/* Error: Type 'string' is not assignable to type 'number'. */}
B: {data.bb({ a: 'hi' })}
{/* You can pass b here, but it won't be typechecked */}
</>
);
}
demo: https://stackblitz.com/edit/react-ts-atcwwh?file=App.tsx
There's other options, but it really depends on your use case.