Common Operators and Signatures Type intersection operator (&) 1 class WithLoading extends React .Component <P & WithLoadingProps > { ... }
Generic function 1 const funcComponent = <P extends object>(Component: React.ComponentType<P>): ... => { ... }
Type cast A type cast (props as P) is required when passing props forward from TypeScript v3.2 onwards, due to a likely bug in TypeScript.
1 return loading ? <LoadingSpinner /> : <Component {...props as P } /> ;
Examples Worth to read:
Higher Order Components Higher Order Component in JS 1 2 3 4 5 6 7 const withLoading = Component => class WithLoading extends React .Component { render ( ) { const { loading, ...props } = this .props; return loading ? <LoadingSpinner /> : <Component {...props } /> ; } };
Higher Order Component in TS 1 2 3 4 5 6 7 8 9 10 11 interface WithLoadingProps { loading: boolean ; } const withLoading = <P extends object>(Component: React.ComponentType<P>) => class WithLoading extends React.Component<P & WithLoadingProps> { render() { const { loading, ...props } = this.props; return loading ? <LoadingSpinner /> : <Component {...props as P} />; } };
Function Higher Order Component in TS 1 2 3 4 5 6 7 const withLoading = <P extends object > ( Component: React.ComponentType<P> ): React.FC<P & WithLoadingProps> => ({ loading, ...props }: WithLoadingProps) => loading ? <LoadingSpinner /> : <Component {...props as P} />;
Render Prop Component 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 interface InjectedCounterProps { value: number ; onIncrement(): void ; onDecrement(): void ; } interface MakeCounterProps { minValue?: number ; maxValue?: number ; children(props: InjectedCounterProps): JSX.Element; } interface MakeCounterState { value: number ; } class MakeCounter extends React .Component <MakeCounterProps , MakeCounterState > { state: MakeCounterState = { value: 0 , }; increment = () => { this .setState(prevState => ({ value: prevState.value === this .props.maxValue ? prevState.value : prevState.value + 1 , })); }; decrement = () => { this .setState(prevState => ({ value: prevState.value === this .props.minValue ? prevState.value : prevState.value - 1 , })); }; render ( ) { return this .props.children({ value: this .state.value, onIncrement: this .increment, onDecrement: this .decrement, }); } }
make-counter-render-prop.tsx
Usage 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 interface CounterProps extends InjectedCounterProps { style: React.CSSProperties; } const Counter = (props: CounterProps) => ( <div style={props.style}> <button onClick={props.onDecrement}> - </button> {props.value} <button onClick={props.onIncrement}> + </button> </div> ); interface WrappedCounterProps extends CounterProps { minValue?: number; maxValue?: number; } const WrappedCounter = ({ minValue, maxValue, ...props }: WrappedCounterProps) => ( <MakeCounter minValue={minValue} maxValue={maxValue}> {injectedProps => <Counter {...props} {...injectedProps} />} </MakeCounter> );
wrapped-counter.tsx
Wrapping Render Prop as HOC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import { Subtract, Omit } from 'utility-types' ;import MakeCounter, { MakeCounterProps, InjectedCounterProps } from './MakeCounter' ;type MakeCounterHocProps = Omit<MakeCounterProps, 'children' >;const makeCounter = <P extends InjectedCounterProps > ( Component: React.ComponentType<P> ): React.SFC<Subtract<P, InjectedCounterProps> & MakeCounterHocProps> => ({ minValue, maxValue, ...props }: MakeCounterHocProps) => ( <MakeCounter minValue={minValue} maxValue={maxValue}> {injectedProps => <Component {...props as P} {...injectedProps} />} </MakeCounter> );
Source: https://medium.com/@jrwebdev/react-render-props-in-typescript-b561b00bc67c
React Hooks Function Components with Hooks in TS example 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import React, { FunctionComponent, useState } from "react" ;const Counter: FunctionComponent<{ initial?: number }> = ({ initial = 0 } ) => { const [clicks, setClicks] = useState(initial); return ( <> <p>Clicks: {clicks}</p> <button onClick={() => setClicks(clicks + 1 )}>+</button> <button onClick={() => setClicks(clicks - 1 )}>-</button> </> ); };
Details about React Hooks with TypeScript
1 2 3 const Counter:FunctionComponent<{ initial?: number }> = ({ initial = 0 } ) => { ... }
with useState
1 2 3 4 5 6 7 8 9 const [value, setValue] = (useState < number ) | (undefined > undefined );const [value, setValue] = useState < Array < number >> [];interface MyObject { foo: string ; bar?: number ; } const [value, setValue] = useState <MyObject> { foo : "hello" };
with useRef
1 const inputEl = useRef <HTMLInputElement> null ;
with useContext
1 2 type Theme = "light" | "dark" ;const ThemeContext = createContext <Theme> "dark" ;
with useReducer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 interface State { value: number ; } type Action = | { type : "increment" } | { type : "decrement" } | { type : "incrementAmount" , amount : number }; const counterReducer = (state: State, action: Action ) => { switch (action.type) { case "increment" : return { value : state.value + 1 }; case "decrement" : return { value : state.value - 1 }; case "incrementAmount" : return { value : state.value + action.amount }; default : throw new Error (); } }; const [state, dispatch] = useReducer(counterReducer, { value : 0 });dispatch({ type : "increment" }); dispatch({ type : "decrement" }); dispatch({ type : "incrementAmount" , amount : 10 }); dispatch({ type : "invalidActionType" });