redux-saga-test-plan
redux-saga-test-plan copied to clipboard
Unexpected typescript type error with expectSaga
Not all the generator functions pass the type check when using expectSaga
. Sometimes unexpected type error is raised if the yields in the function are mixed by saga effects and normal generator functions.
// Example
import { expectSaga } from "redux-saga-test-plan";
import { select } from "redux-saga/effects";
function* dummyGenerator(name: string) {
yield select();
console.log(name);
}
function* dummySagaFn() {
const name: string = yield select(); // Type the return value. Important to reproduce the issue
yield dummyGenerator(name);
}
it("", async () => {
expectSaga(dummySagaFn).withState({ name: "test-name" }).run(); // type error
});
Sample code (line 15): https://codesandbox.io/s/cranky-resonance-47uuz?file=/src/demo.test.ts Typescript version: 4.5
// Source code
interface Iterator<T, TReturn = any, TNext = undefined> {
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
return?(value?: TReturn): IteratorResult<T, TReturn>;
throw?(e?: any): IteratorResult<T, TReturn>;
}
interface IterableIterator<T> extends Iterator<T> {
[Symbol.iterator](): IterableIterator<T>;
}
export type SagaType = (...params: any[]) => SagaIterator | IterableIterator<any>;
export const expectSaga: (<S extends SagaType>(
generator: S,
...sagaArgs: Parameters<S>
) => ExpectApi) & { DEFAULT_TIMEOUT: number };
The issue is in SagaType. IterableIterator<any>
extends Iterator<T>
. The TNext
is default to undefined
. If we type one of the return values of yield
statements (line 10 in the example), the error occurs.
Potential solution:
Change SagaType to export type SagaType = (...params: any[]) => SagaIterator | Generator<any>;