Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript React stateless function with generic parameter/return types

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>;
  ...
}
like image 587
Jurosh Avatar asked Jun 06 '17 14:06

Jurosh


People also ask

What is typescript generics and how to use it?

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.

When to declare return type in typescript?

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 */

Why is there a trailing comma in <objecttype> in typescript?

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

Why can’t static members use the type parameter of a generic class?

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.


1 Answers

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} />;
like image 95
Jokester Avatar answered Sep 20 '22 21:09

Jokester