异步调度值的 TypeScript 类型
TypeScript type of an async dispatch value
我有以下异步操作定义:
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;
});
}
}
上面的类型检查没问题。
我也理解当您调用 dispatch
并向其传递异步操作时,如下所示:
dispatch(asynAction())
… 然后是 return 类型如果是内部函数的类型,所以我希望上面值的类型是 Promise<number>
。但是以下内容不进行类型检查:
function foo (dispatch: Dispatch<any>) {
const n: Promise<number> = dispatch(asyncAction()); // line A
}
具体来说,我在 line A
上收到以下错误:
TS2322: Type 'void' is not assignable to type 'Promise<number>'
所以,为了满足TS,我不得不做类似下面感觉不对的事情:
const n: Promise<number> = dispatch(asyncAction()) as unknown as Promise<number>;
我错过了什么?
更新
我的 `package.json` 有:
"@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>
的地方),像这样:
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);
}
…我得到一个不同的错误:
TS2739: Type '(dispatch: ThunkDispatch<any, any, any>) => Promise<number>' is missing the following properties from type 'Promise<number>': then, catch, [Symbol.toStringTag]
不同的包对Dispatch
类型有不同的定义。您从 'react' 导入的那个不符合您的需要。
Redux 声明调度 return 动作:
export interface Dispatch<A extends Action = AnyAction> {
<T extends A>(action: T): T
}
React,为了它自己的 useReducer
钩子(redux-lite)定义了 Dispatch
,说它 return 什么都没有:
type Dispatch<A> = (value: A) => void;
Thunk 有一个更复杂的定义,允许它 return 任何基于泛型的任意 return 类型:
export interface Dispatch<A extends Action = AnyAction> {
<TReturnType = any, TState = any, TExtraThunkArg = any>(
thunkAction: ThunkAction<TReturnType, TState, TExtraThunkArg, A>,
): TReturnType;
}
您的第一个示例之所以有效,是因为您实际上从未调用过 dispatch
函数,并且您的 return 类型与 axios
调用中的 return 类型相匹配。您在第二个示例中遇到了同样的问题。
asyncAction()
不调度操作。 Promise<number>
是动作创建者 的 return 类型 ,而不是调度的。关于缺少属性的错误基本上是在告诉您调度不会 return a Promise
.
你写的 asyncAction
非常混乱,但基本上它是一个函数,return 是一个接受 dispatch
和 return 的函数s Promise<number>
。因此,基于此,在 foo
中获得 Promise<number>
的方式不是通过使用函数调用 dispatch
,而是将 dispatch
作为参数传递给通过调用创建的函数ayncAction()
.
export function foo (dispatch: Dispatch<any, any, any>) {
const n: Promise<number> = asyncAction()(dispatch);
console.log(n);
}
这当然是没有意义的,因为你仍然没有在任何地方发送任何东西。
编辑:
希望这对您打算做的事情有所帮助。希望从 dispatch
的 return 值中得到 n
只是为了测试,因为你不能也不应该那样做。
让我们定义我们最终将派发的操作,以及它的创建者。
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
作为参数并且 return 是一个 Promise
作为它最终调度的动作的函数。
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
这个,但它 return 是 ThunkAction
本身。换句话说,调用 dispatch
return 是一个需要 dispatch
的函数。所以你不能从调度 thunk 的 return 值中得到任何有意义的东西。
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);
}
我有以下异步操作定义:
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;
});
}
}
上面的类型检查没问题。
我也理解当您调用 dispatch
并向其传递异步操作时,如下所示:
dispatch(asynAction())
… 然后是 return 类型如果是内部函数的类型,所以我希望上面值的类型是 Promise<number>
。但是以下内容不进行类型检查:
function foo (dispatch: Dispatch<any>) {
const n: Promise<number> = dispatch(asyncAction()); // line A
}
具体来说,我在 line A
上收到以下错误:
TS2322: Type 'void' is not assignable to type 'Promise<number>'
所以,为了满足TS,我不得不做类似下面感觉不对的事情:
const n: Promise<number> = dispatch(asyncAction()) as unknown as Promise<number>;
我错过了什么?
更新
我的 `package.json` 有:"@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>
的地方),像这样:
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);
}
…我得到一个不同的错误:
TS2739: Type '(dispatch: ThunkDispatch<any, any, any>) => Promise<number>' is missing the following properties from type 'Promise<number>': then, catch, [Symbol.toStringTag]
不同的包对Dispatch
类型有不同的定义。您从 'react' 导入的那个不符合您的需要。
Redux 声明调度 return 动作:
export interface Dispatch<A extends Action = AnyAction> {
<T extends A>(action: T): T
}
React,为了它自己的 useReducer
钩子(redux-lite)定义了 Dispatch
,说它 return 什么都没有:
type Dispatch<A> = (value: A) => void;
Thunk 有一个更复杂的定义,允许它 return 任何基于泛型的任意 return 类型:
export interface Dispatch<A extends Action = AnyAction> {
<TReturnType = any, TState = any, TExtraThunkArg = any>(
thunkAction: ThunkAction<TReturnType, TState, TExtraThunkArg, A>,
): TReturnType;
}
您的第一个示例之所以有效,是因为您实际上从未调用过 dispatch
函数,并且您的 return 类型与 axios
调用中的 return 类型相匹配。您在第二个示例中遇到了同样的问题。
asyncAction()
不调度操作。 Promise<number>
是动作创建者 的 return 类型 ,而不是调度的。关于缺少属性的错误基本上是在告诉您调度不会 return a Promise
.
你写的 asyncAction
非常混乱,但基本上它是一个函数,return 是一个接受 dispatch
和 return 的函数s Promise<number>
。因此,基于此,在 foo
中获得 Promise<number>
的方式不是通过使用函数调用 dispatch
,而是将 dispatch
作为参数传递给通过调用创建的函数ayncAction()
.
export function foo (dispatch: Dispatch<any, any, any>) {
const n: Promise<number> = asyncAction()(dispatch);
console.log(n);
}
这当然是没有意义的,因为你仍然没有在任何地方发送任何东西。
编辑:
希望这对您打算做的事情有所帮助。希望从 dispatch
的 return 值中得到 n
只是为了测试,因为你不能也不应该那样做。
让我们定义我们最终将派发的操作,以及它的创建者。
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
作为参数并且 return 是一个 Promise
作为它最终调度的动作的函数。
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
这个,但它 return 是 ThunkAction
本身。换句话说,调用 dispatch
return 是一个需要 dispatch
的函数。所以你不能从调度 thunk 的 return 值中得到任何有意义的东西。
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);
}