Practical TypeScript. React + Redux
Tags: react, redux, typescript
Published: 2018-11-29 21:44:47

---
title: Practical TypeScript. React + Redux
published: true
description: Tremendous power of TypeScript
tags: react, redux, typescript
---

###Preface

Today any modern front-end development process that more complex than `hello world` application, where different teams works under the one project, makes high demands to code quality. In order to hold the high quality code in our `#gostgroup` front-end team we keep up with the times and don't afraid use modern technologies that show their practical benefits on the example of some projects of [different size companies](https://www.typescriptlang.org/community/friends.html).

There are many articles about benefits of a static typing on the example of TypeScript, but today we focus on more practical issues from our favorite (in `#gostgroup`, I think your too) front-end stack (React + Redux).

### "I don't know how do you live at all without a strong static typing. What do you do? Debug your code all day?" - unknown person.
### "No, we write types all day." - my colleague.

Many people complain to a fact what writing code in TypeScript (here and next I mean subject stack) enforce you to spend much time on coding types manually. A good example of this is `connect` function from `react-redux` library:

```typescript
type Props = {
  a: number,
  b: string;
  action1: (a: number) => void;
  action2: (b: string) => void;
}

class Component extends React.PureComponent<Props> { }

connect(
  (state: RootStore) => ({
    a: state.a,
    b: state.b,
  }), {
    action1,
    action2,
  },
)(Component);
```

What is the problem here? As you can see for every new injected property passed via connector we must declare the property type in common React component property types. Very boring stuff. It is would be a cool thing if we have a possibility to automatically merge all connector injected property types in to one general type and just join this type with common React component property types. I have good news for you. Right now we able to do this awesome typing with TypeScript. Ready? Go!


###Super force of TypeScript

TypeScript doesn't stagnate for a long time and rapidly progress (I like it very much). Beginning from a version of 2.8 we got very interesting feature (conditional types) that allow us to "to express non-uniform type mappings". I will not be stopping here for giving you deep explanation about this feature and just leave [a link to the documentation](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html) with example from this one:


```typescript
type TypeName<T> =
  T extends string ? "string" :
  T extends number ? "number" :
  T extends boolean ? "boolean" :
  T extends undefined ? "undefined" :
  T extends Function ? "function" :
  "object";

type T0 = TypeName<string>;  // "string"
type T1 = TypeName<"a">;  // "string"
type T2 = TypeName<true>;  // "boolean"
type T3 = TypeName<() => void>;  // "function"
type T4 = TypeName<string[]>;  // "object"
```

And how this feature can help us with our problem? In [`react-redux` library typings](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-redux/index.d.ts) there is `InferableComponentEnhancerWithProps` type that hides injected property types from public component interface (properties that we must pass explicitly when we instantiate a component via `JSX`). `InferableComponentEnhancerWithProps` type has two generic type parameters: `TInjectedProps` and `TNeedsProps`. We interested in first one. Let's try to "pull" this type from real connector!

```typescript
type TypeOfConnect<T> = T extends InferableComponentEnhancerWithProps<infer Props, infer _>
  ? Props
  : never
;
```

And let me show a real working example from [repository](https://github.com/Voronar/ts-react-redux/blob/master/src/App.tsx):


```typescript
import React from 'react';
import { connect } from 'react-redux';

import { RootStore, init, TypeOfConnect, thunkAction, unboxThunk } from 'src/redux';

const storeEnhancer = connect(
  (state: RootStore) => ({
    ...state,
  }), {
    init,
    thunkAction: unboxThunk(thunkAction),
  }
);

type AppProps = {}
  & TypeOfConnect<typeof storeEnhancer>
;

class App extends React.PureComponent<AppProps> {
  componentDidMount() {
    this.props.init();
    this.props.thunkAction(3000);
  }
  render() {
    return (
      <>
        <div>{this.props.a}</div>
        <div>{this.props.b}</div>
        <div>{String(this.props.c)}</div>
      </>
    );
  }
}

export default storeEnhancer(App);
```

In example above we divide connection to store in two phases. In first one we assign redux store enhancer to `storeEnhancer` variable (it has `InferableComponentEnhancerWithProps` type) for extracting injected property types with our `TypeOfConnect` type-helper and just join inferred type with own component property types via intersection operator `&`. In second phase we decorate our source component. Now whatever property you add to connector it will always be in our component property types. Awesome! It is all we wanted to achieve!

Mind-coder noticed that thunk actions wrapped with special `unboxThunk` function. Why we done this? Let's puzzle out this thing. First of all let's see thunk action signature of tutorial application from repo:

```typescript
const thunkAction = (delay: number): ThunkAction<void, RootStore, void, AnyAction> => (dispatch) => {
  console.log('waiting for', delay);
  setTimeout(() => {
    console.log('reset');
    dispatch(reset());
  }, delay);
};
```

As we can see in function signature, thunk action doesn't immediately return main action body, but it returns special function for redux middleware dispatcher. It is common way to make side effects in redux actions. However when we use a bound version of this action in component it has "cutted" form without middle function. How to declare this changeable function signature? We need a special transformer. And again TypeScript shows us his super force. For a start let's declare a type that cut of middle function from any function signature:

```typescript
CutMiddleFunction<T> = T extends (...arg: infer Args) => (...args: any[]) => infer R
  ? (...arg: Args) => R
  : never
;
```
Here we use another cool newcomer from TypeScript 3.0 that allow us to infer function rest parameter types (for more detail see [the documentation](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html)). Next we can define (with little hard type assertion) our "function-cutter":

```typescript
const unboxThunk = <Args extends any[], R, S, E, A extends Action<any>>(
  thunkFn: (...args: Args) => ThunkAction<R, S, E, A>,
) => (
  thunkFn as any as CutMiddleFunction<typeof thunkFn>
);
```
And now we only have to wrap out our source thunk action with this transformer and use it in connector.


In such a simple way we reduce our manual work with types. If you want to go deeper you could try [redux-modus](https://www.npmjs.com/package/@gostgroup/redux-modus) library that simplify action and reducer creation in type safety way.

**P.S** When you will try to use actions binding util like `redux.bindActionCreators` you will have to take care of more right type inference that not working out of the box.

**Update 0**
If someone liked this solution you could [make thumb up](https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31227#issuecomment-446681805) to see this utility type in `@types/react-redux` package.

**Update 1**

Some useful util types. No more need to manually declare injected property types for hoc's. Just give you hoc and extract its injected property types automatically:

```typescript
export type BasicHoc<T> = (Component: React.ComponentType<T>) => React.ComponentType<any>;
export type ConfiguredHoc<T> = (...args: any[]) => (Component: React.ComponentType<T>) => React.ComponentType<any>;

export type BasicHocProps<T> = T extends BasicHoc<infer Props> ? Props : never;
export type ConfiguredHocProps<T> = T extends ConfiguredHoc<infer Props> ? Props : never;

export type HocProps<T> = T extends BasicHoc<any>
  ? BasicHocProps<T> : T extends ConfiguredHoc<any>
  ? ConfiguredHocProps<T> : never
;

const basicHoc = (Component: React.ComponentType<{a: number}>) => class extends React.Component {};
const configuredHoc = (opts: any) => (Component: React.ComponentType<{a: number}>) => class extends React.Component {};

type props1 = HocProps<typeof basicHoc>; // {a: number}
type props2 = HocProps<typeof configuredHoc>; // {a: number}
```

**Update2**
Merged to `react-redux` upstream code base in form of [ConnectedProps](https://react-redux.js.org/using-react-redux/static-typing#recommendations) type.