How to define generic type in React stateless components based on parameter, or outside configuration?
Example component:
interface IProps<V> {
value: V;
doSomething: (val: V) => void;
}
const Comp: React.SFC<IProps<number>> = <T extends number>({
value: T,
doSomething
}) => {
return <div />;
}
Above example will work, but only with numbers as values.
Is possible to do upgrade to achieve something like:
const Comp: React.SFC<IProps<??>> = <?? extends string | number>({
value, /* of type ?? */
doSomething
}) => {
return <div />;
}
So that we can decide whatever we want numbers, or strings when using component.
Desired usage:
// This should setup generic type to string
<Comp value="string" ... />
// Or number
<Comp value={123} ... />
// Should be compilation error as we cannot use * on 'text' * 5
<Comp value="text" doSomething={val => val * 5} />
Edit: Should do same job as function
does:
function Comp <T>({value, doSomething}: IProps<T>) { ... }
SFC Type has definition:
interface SFC<P> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any>;
...
}
TypeScript Generics is a tool that provides a way to create reusable components. It creates a component that can work with a variety of data types rather than a single data type. It allows users to consume these components and use their own types. Generics ensures that the program is flexible as well as scalable in the long term.
My personal style is to declare return type if it is a large function (i.e. more than 5 lines). If it is a short function that just do simple computation, I will just let TypeScript do its magic. /* rest params work just as you'd think. Type must be array-ish */
The trailing comma in <ObjectType, > is added due to contraints of the .tsx file extension. You can read more in the TypeScript Generics. Discussing naming conventions
Generic classes are only generic over their instance side rather than their static side, so when working with classes, static members can not use the class’s type parameter.
I was able to do this in TS 2.3. The point is to use 2 types for "inside" and "outside" of that component.
interface IProps<V> {
value: V;
doSomething(val: V): void;
}
// type "inside" component
function _Comp<T>(props: IProps<T>) {
return <div />;
}
// type for "outside" of component
interface GenericsSFC extends React.SFC<any> {
<T>(props: IProps<T> & { children?: React.ReactNode }, context?: any): JSX.Element;
}
const Comp = _Comp as GenericsSFC;
// dont type check: v is of type "hey"
<Comp value={"hey"} doSomething={v => v - 1} />;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With