将承诺与承诺中间件 + thunk 链接时"Property 'then' does not exist"打字稿错误



我使用带有redux thunk的redux promise中间件来链接我的promise:

import { Dispatch } from 'redux';
class Actions {
private static _dispatcher: Dispatch<any>;
public static get dispatcher(): Dispatch<any> {
return Actions._dispatcher;
}
public static test() {
this.dispatcher({
type: 'MY_ACTION',
payload: new Promise(resolve => resolve('hi'));
}).then(result => {
console.log(result); // this works
});
}
}

上面的代码有效,但在编译时也会生成警告:

TS2339:类型"{type:string;有效载荷:Promise<{}>;}'

听起来我需要在某个地方包含Promise<...>作为类型,这样typescript就知道then实际上是dispatcher()返回的对象上的一个属性,但我无法删除错误。

https://github.com/gaearon/redux-thunk/issues/103

import { Dispatch } from 'redux';
import { ThunkAction } from 'redux-thunk';
import { getStore, IState } from './my_store';
let store = getStore();
// Create myThunkAction function with a type of ThunkAction<R, S, E>
let myThunkAction: ThunkAction<Promise<string>, IState, null> =
(dispatch: Dispatch<IState>, getState: () => IState) => {
return new Promise<string>((resolve, reject) => {
// do async stuff with getState() and dispatch(), then...
resolve('done!');
});
}
store.dispatch(myThunkAction)
.then(() => {
// do stuff after the thunk has finished...
});

似乎相关,但我可以在哪里指定操作类型,即MY_ACTION

正如您在这个ts操场上看到的,变量a暴露了与Dispatch<any>类型相同的键,正如您所看到的,如果您将鼠标悬停在错误上,错误消息与您的情况相同。为了访问promise(以及then函数),您必须访问Dispatch对象的payload

this.dispatcher({ ... }).payload.then(....);

第1版:

如果我们查看redux的打字法,我们可以很快找到Dispatcher接口。

export interface Dispatch<S> {
<A extends Action>(action: A): A;
}
export interface Action {
type: any;
} 

然后通过一些重写和对psudode的一些自由使用,我们可以推断Dispatch的类型是一个函数,它接受一个参数witch是一个对象,并返回一个与该参数类型相同的对象。

type Dispatch: (action: {type: any, ...}) => {type: any, ...}

输入对象和输出对象都属于以下类型:

interface {
type: any,
[key: string]: value
}

总之,1)你没有使用redux的官方打字法,2)redux的正式打字法是错误的,或者3)你在生活环境中错过了一些东西,而实际上代码不起作用。

第2版:

我还没有尝试过这个代码,所以我不知道它是否真的能解决你的问题。但是您可以尝试重新定义Dispatch接口。

declare module 'redux' {
export interface Action {
type: any;
}
export interface Dispatch<S> {
<A extends Action>(action: A): Promise<S>;
}
}

正如你在这个操场上看到的那样,这是一个有效的打字稿,但我以前从来没有这样做过,所以这可能不会开箱即用。

如果这不起作用,您可以尝试定义一个与模块同名的命名空间。

namespace redux {
export interface Action {
type: any;
}
export interface Dispatch<S> {
<A extends Action>(action: A): Promise<S>;
}
}

不过我以前还没有尝试过,所以我不能保证它会起作用。

最新更新