Typescript: использовать типы по вызову () от redux-saga - PullRequest
0 голосов
/ 23 октября 2019

Как я могу установить типы функций, используя call()?

У меня есть эта функция:

export function apiFetch<T>(url: string): Promise<T> {
    return fetch(url).then(response => 
        {
            if (!response.ok) throw new Error(response.statusText)
            return response.json().then(data => data as T);
        }
    )  
}

Эта функция может использоваться как:

let resp = await apiFetch<ServerResponse>("http://localhost:51317/Task");

Используя функцию, как вы можете видеть в приведенном выше фрагменте кода, resp правильно вводится в виде строки. Таким образом, intellisense предлагает мне все атрибуты интерфейса ServerResponse.

Однако эта функция должна вызываться внутри рабочего из redux-saga, который не разрешает асинхронные функции:

function* refreshTaskSaga():any {
    yield takeEvery("TASK_REFRESH", workerRefreshTaskSaga);
}


function* workerRefreshTaskSaga() {
  //I need to call the function here
}

Я пытаюсь вызвать его с помощью yield + call, как сказано в документации redux-saga:

a) let resp = yield call(apiFetch, "http://localhost:51317/Task");
b) let resp = yield call(apiFetch<ServerResponse>, "http://localhost:51317/Task");

Первый вариант - выполнить функцию, как ожидается, однако resp имеет тип any. Второй вариант вызывает у меня исключение.

No overload matches this call.
  The last overload gave the following error.
    Argument of type 'boolean' is not assignable to parameter of type '{ context: unknown; fn: (this: unknown, ...args: any[]) => any; }'.ts(2769)
effects.d.ts(499, 17): The last overload is declared here.

Есть идеи о правильном синтаксисе, чтобы вызывать его и не терять типы?

1 Ответ

1 голос
/ 23 октября 2019

К сожалению, левая сторона yield всегда имеет тип any. Это потому, что функция генератора в принципе может быть возобновлена ​​с любым значением. Redux saga ведет себя предсказуемо при запуске генераторов, но ничто не мешает кому-то писать другой код, который проходит через вашу сагу и дает вам значения, не связанные с тем, что вы получили, например:

const iterator = workerRefreshTaskSaga();
iterator.next();
// You might have been expecting a ServerResponse, but too bad, you're getting a string.
iterator.next('hamburger'); 

Onlyесли вы можете предположить, что в вашем генераторе используется редукс-сага, можете ли вы делать прогнозы о типах, а у машинописного текста нет способа сказать: «предположим, что этот генератор будет запускаться сагой-редуктом (и всеми вытекающими последствиями)».

Так что вам нужно будет добавить типы самостоятельно. Например:

const resp: ServerResponse = yield call(apiFetch, 'url');

Это означает, что вы несете ответственность за правильность типов. Поскольку машинопись может только сказать, что это any, она будет доверять вам то, что вы говорите, типа. Таким образом, машинопись может проверить, что код, следующий за этим, правильно взаимодействует с ServerResponse, но если на самом деле это не ServerResponse, машинопись не может указать вам на это.

Одна вещь, которую я часто делаю, чтобы получитьнемного больше безопасности типов - это использование ReturnType, например:

const output: ReturnType<someFunction> = yield call(someFunction);

Мне все еще нужно знать, что ReturnType<someFunction> правильно, но, если я это сделал, то если кто-то изменит реализацию someFunctionчтобы заставить его возвращать что-то другое, тип вывода будет обновлен для соответствия.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...