异步调度值的TypeScript类型 [英] TypeScript type of an async dispatch value

查看:93
本文介绍了异步调度值的TypeScript类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下异步操作定义:

I have the following async action definition:

import {Dispatch} from 'react';
import axios, {AxiosResponse, AxiosError} from 'axios';

function asyncAction() {
    return (dispatch: Dispatch<any>): Promise<number> => {
        return axios.get('http://www.example.com')
            .then( (res: AxiosResponse<any>) => {
                return 1;
            })
            .catch( (err: AxiosError<any>) => {
                return 2;
            });
    }
}

上面的类型检查得很好.

The above typechecks fine.

我还了解到,当您调用 dispatch 并将其传递给异步操作时,就像这样:

I also understand that when you call dispatch and pass it an asynchronous action, like so:

dispatch(asynAction())

…如果是内部函数,则返回类型,因此我希望上述值的类型为 Promise< number> .但是以下内容不会进行类型检查:

… then the return type if that of the inner function, so I would expect the type of the above value to be Promise<number>. Yet the following does not typecheck:

function foo (dispatch: Dispatch<any>) {
    const n: Promise<number> = dispatch(asyncAction()); // line A
}

具体来说,我在 A行上收到以下错误:

Specifically, I get the following error on line A:

TS2322: Type 'void' is not assignable to type 'Promise<number>'

因此,为了满足TS,我必须做类似以下事情的感觉:

So, in order to satisfy TS, I have to do something like the following which feels wrong:

const n: Promise<number> = dispatch(asyncAction()) as unknown as Promise<number>;

我想念什么?

"@types/react-redux": "^7.1.9",
"react-redux": "^7.2.0",
"redux": "^4.0.5",
"redux-devtools-extension": "^2.13.8",
"redux-thunk": "^2.3.0"

当我执行以下操作时:

import {ThunkDispatch as Dispatch} from 'redux-thunk';

…,并使用导入的 ThunkDispatch 类型作为 ThunkDispatch< any,any,any> (只要我在其中的 Dispatch< any> 上面的代码),就像这样:

… and use the imported ThunkDispatch type as ThunkDispatch<any, any, any> (wherever I have Dispatch<any> in the above code), like so:

import axios, {AxiosResponse
             , AxiosError} from 'axios';
import {ThunkDispatch as Dispatch} from 'redux-thunk';

export function asyncAction() {
    return (dispatch: Dispatch<any, any, any>): Promise<number> => {
        return axios.get('http://www.example.com')
            .then( (res: AxiosResponse<any>) => {
                return 1;
            })
            .catch( (err: AxiosError<any>) => {
                return 2;
            });
    }
}

export function foo (dispatch: Dispatch<any, any, any>) {
    const n: Promise<number> = dispatch(asyncAction());
    console.log(n);
}

...我得到了另一个错误:

… I get a different error:

  TS2739: Type '(dispatch: ThunkDispatch<any, any, any>) => Promise<number>' is missing the following properties from type 'Promise<number>': then, catch, [Symbol.toStringTag]

推荐答案

不同的包对于 Dispatch 类型具有不同的定义.您正在从反应"中导入一个,这不符合您的需求.

Different packages have different definitions for the Dispatch type. You are importing the one from 'react', which does not suit your needs.

Redux声明分派返回操作:

Redux declares that a dispatch returns the action:

export interface Dispatch<A extends Action = AnyAction> {
  <T extends A>(action: T): T
}

React为自己的 useReducer 钩子(redux-lite)定义了 Dispatch ,它说什么都不返回:

React, which defines Dispatch for the purposes of it's own useReducer hook (redux-lite), says that it returns nothing:

type Dispatch<A> = (value: A) => void;

Thunk的定义要复杂得多,它可以基于泛型返回任意的返回类型:

Thunk has a much more complicated definition which allows it to return any arbitrary return type base on a generic:

export interface Dispatch<A extends Action = AnyAction> {
    <TReturnType = any, TState = any, TExtraThunkArg = any>(
      thunkAction: ThunkAction<TReturnType, TState, TExtraThunkArg, A>,
    ): TReturnType;
  }

您的第一个示例之所以有效,是因为您从未真正调用过 dispatch 函数,并且您返回的类型与 axios 调用中的返回类型相匹配.在第二个示例中,您遇到了同样的问题.

Your first example worked because you never actually called the dispatch function and you return type matched the return type from the axios call. You're having the same problem in your second example.

asyncAction()不会分派动作. Promise< number> 是动作创建者的返回类型 ,而不是调度的返回类型.有关缺少属性的错误基本上是在告诉您,调度不会返回 Promise .

asyncAction() doesn't dispatch the action. Promise<number> is the return type of the action creator, not of the dispatch. The error about missing properties is basically telling you that the dispatch doesn't return a Promise.

您已经以一种非常混乱和混乱的方式编写了 asyncAction ,但是从根本上讲,它是一个函数,该函数返回需要 dispatch 并返回 Promise<; number> .因此,基于此,在 foo 中获得 Promise< number> 的方式不是通过函数调用 dispatch ,而是通过传递 dispatch 作为通过调用 ayncAction()创建的函数的参数.

You've written asyncAction in a very confused and confusing way, but basically it is a function which returns a function which takes a dispatch and returns Promise<number>. So based on that, the way you get Promise<number> in foo is not by calling dispatch with your function, but by passing dispatch as the argument to the function created by calling ayncAction().

export function foo (dispatch: Dispatch<any, any, any>) {
    const n: Promise<number> = asyncAction()(dispatch);
    console.log(n);
}

这当然是没有意义的,因为您仍然不会在任何地方分派任何东西.

This of course makes no sense, since you still never dispatch anything anywhere.

打字机游乐场链接

希望这对您要完成的工作有所帮助.希望从 dispatch 的返回值中获得 n 只是用于测试,因为您不能也不应这样做.

Hopefully this helps with what you're tying to do. Hopefully getting n from the return value of the dispatch was just for testing because you can't and shouldn't do that.

让我们定义我们最终将要分派的动作,以及它的创建者.

Let's define the action that we will ultimately dispatch, along with a creator for it.

import { Action } from "redux";

// normal action type
interface NumberAction extends Action {
    payload: number;
}

// normal action creator
function sendNumber(number: number): NumberAction {
    return { type: 'SEND_NUMBER', payload: number };
}

我们创建一个 ThunkAction 来调度此 NumberAction .该函数以 dispatch 作为参数,并为其最终调度的操作返回 Promise .

We make a ThunkAction that dispatches this NumberAction. It is a function that takes dispatch as an argument and returns a Promise for the action that it ultimately dispatches.

const myThunkAction1: ThunkAction<Promise<NumberAction>, any, any, NumberAction> = (dispatch): Promise<NumberAction> => {
    return axios.get('http://www.example.com')
        .then((res: AxiosResponse<any>) => {
            return 1;
        })
        .catch((err: AxiosError<any>) => {
            return 2;
        })
        .then(number => dispatch(sendNumber(number)));
}

我们可以 dispatch ,但是它返回 ThunkAction 本身.换句话说,调用 dispatch 返回一个采用 dispatch 的函数.因此,从分派thunk的返回值中您将无法获得任何有意义的东西.

We can dispatch this, but it returns the ThunkAction itself. In other words, calling dispatch returns a function which takes dispatch. So you cannot get anything meaningful from the return value of dispatching a thunk.

export function foo(dispatch: Dispatch<any, any, any>) {
    // still doesn't return Promise<number>, returns the ThunkAction
    const returned = dispatch(myThunkAction2);
    // can only get to Promise<number> by calling the returned thunk, which would re-dispatch the action
    const n: Promise<number> = returned(dispatch, () => {}, {});
    console.log(n);
}

第二个游乐场链接

这篇关于异步调度值的TypeScript类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆