Skip to content

Instantly share code, notes, and snippets.

@retyui
Last active Oct 27, 2020
Embed
What would you like to do?
HOW USE FLOW.JS WITH REDUX-SAGA

These examples for:

Install or update typings

flow-typed install # for initial run

flow-typed update # when you have types

Saga

Use Saga for typing all generator function

import type { Saga } from 'redux-saga';

// Here we use `Saga<T>` , where `T` is return type

function* emptySaga(): Saga<void> { }

function* getNumber(): Saga<number> {
  return 69;
}

Problems with Saga

Let's look at thetype of Saga

declare export type Saga<T> = Generator<Effect, T, any>;

// interface Generator<+Yield,+Return,-Next> { /*...*/}

How you can see all Next values will be have any type.

I hope I don't need to explain why the type of any is so dangerous.

For example we have some async function fetchItems and saga which calls this function:

type Item = {| id: number, name: string |};

declare var fetchItems: (offset: number) => Promise<Array<Item>>;

// --------------------------------------------------------------
import type { Saga } from 'redux-saga';
import { call, put, takeEvery, select } from 'redux-saga/effects';

function* watchPullToPrefreshBad(): Saga<Array<Item>> {
  
  const result = yield call(fetchItems, 0); // `result: any` always 

  // Error in runtime `TypeError: {}.abraCadabra is not a function`
  result.abraCadabra(); 

  return result.slice(0, 3);
}

How we can help Flow.js find this error?

From my point of view, we should prompt type.

// But first, let's add some help types
type _ReturnValue<Return, Fn: (...args: *) => Return> = Return;
type _ExtractPromiseType<ReturnType, P: Promise<ReturnType>> = ReturnType;

type ReturnValue<Fn> = _ReturnValue<*, Fn>;
type ExtractPromiseType<P> = _ExtractPromiseType<*, P>;
type AsyncReturnValue<Fn> = ExtractPromiseType<ReturnValue<Fn>>;

// -----------------------------------------------------------------------

import type { Saga } from 'redux-saga';
import { call, put, takeEvery, select } from 'redux-saga/effects';

function* watchPullToPrefreshBetter(): Saga<Array<Item>> {
  const result: AsyncReturnValue<typeof fetchItems> = yield call(fetchItems, 0);

  // Flow.js: Cannot call `result.abraCadabra` because property `abraCadabra` is missing in `Array` [1].
  result.abraCadabra();

  return result.slice(0, 3);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment