These examples for:
- [email protected]
[email protected]
and above
flow-typed install # for initial run
flow-typed update # when you have types
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;
}
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);
}