我有一个使用React和Redux的TypeScript项目,我正在尝试添加一些中间件函数.我开始实现Redux的样本中的一个样本:
// ---- middleware.ts ----
export type MiddlewareFunction = (store: any) => (next: any) => (action: any) => any;
export class MyMiddleWare {
public static Logger: MiddlewareFunction = store => next => action => {
// Do stuff
return next(action);
}
}
// ---- main.ts ----
import * as MyMiddleware from "./middleware";
const createStoreWithMiddleware = Redux.applyMiddleware(MyMiddleWare.Logger)(Redux.createStore);
Run Code Online (Sandbox Code Playgroud)
上面的工作正常,但由于这是TypeScript,我想使它强类型,理想情况下使用Redux定义的类型,所以我不必重新发明和维护自己的类型.因此,以下是我的Redux的index.d.ts文件的相关摘录:
// ---- index.d.ts from Redux ----
export interface Action {
type: any;
}
export interface Dispatch<S> {
<A extends Action>(action: A): A;
}
export interface MiddlewareAPI<S> {
dispatch: Dispatch<S>;
getState(): S;
}
export interface Middleware {
<S>(api: MiddlewareAPI<S>): (next: Dispatch<S>) => Dispatch<S>;
}
Run Code Online (Sandbox Code Playgroud)
我试图找出如何将这些类型带入我的Logger方法,但我没有太多运气.在我看来,这样的事情应该有效:
interface MyStore {
thing: string;
item: number;
}
interface MyAction extends Action {
note: string;
}
export class MyMiddleWare {
public static Logger: Middleware = (api: MiddlewareAPI<MyStore>) => (next: Dispatch<MyStore>) => (action: MyAction) => {
const currentState: MyStore = api.getState();
const newNote: string = action.note;
// Do stuff
return next(action);
};
}
Run Code Online (Sandbox Code Playgroud)
但我得到这个错误:
错误TS2322:输入'(api:MiddlewareAPI)=>(next:Dispatch)=>(action:Action)=> Action'不能分配给'Middleware'类型.
参数"api"和"api"的类型不兼容.
类型'MiddlewareAPI'不能分配给'MiddlewareAPI'类型.
类型"S"不能分配给"MyStore"类型.
我看到在类型定义中声明的<S>泛型,但我尝试了很多不同的组合,我似乎无法弄清楚如何将其指定为MyStore,以便在其余部分中将其识别为泛型类型声明.例如,根据声明api.getState()应该返回一个MyStore对象.当然,同样的想法也适用于动作类型<A>.
小智 10
MyStore不是必需的.
export const Logger: Middleware =
(api: MiddlewareAPI<void>) =>
(next: Dispatch<void>) =>
<A extends Action>(action: A) => {
// Do stuff
return next(action);
};
Run Code Online (Sandbox Code Playgroud)
要么
export const Logger: Middleware = api => next => action => {
// Do stuff
return next(action);
};
Run Code Online (Sandbox Code Playgroud)
有一个漂亮的开发
小智 6
这是我的解决方案:
首先是接受 todo 函数作为输入的中间件创建者,该函数作为中间件的核心逻辑运行。待办函数接受一个对象,封装store(MiddlewareAPI<S>),next(Dispatch<S>),action(Action<S>)以及其他任何你custimized参数。请注意,我as Middleware用来强制中间件创建者返回一个中间件。这是我用来摆脱麻烦的魔法。
import { MiddlewareAPI, Dispatch, Middleware } from 'redux';
import { Action } from 'redux-actions';
export interface MiddlewareTodoParams<S> {
store: MiddlewareAPI<S>;
next: Dispatch<S>;
action: Action<S>;
[otherProperty: string]: {};
}
export interface MiddlewareTodo<S> {
(params: MiddlewareTodoParams<S>): Action<S>;
}
// <S>(api: MiddlewareAPI<S>): (next: Dispatch<S>) => Dispatch<S>;
export const createMiddleware = <S>(
todo: MiddlewareTodo<S>,
...args: {}[]
): Middleware => {
return ((store: MiddlewareAPI<S>) => {
return (next: Dispatch<S>) => {
return action => {
console.log(store.getState(), action.type);
return todo({ store, next, action, ...args });
};
};
// Use as Middleware to force the result to be Middleware
}) as Middleware;
};
Run Code Online (Sandbox Code Playgroud)
第二部分是我的 todo 函数的定义。在这个例子中,我将一些令牌写入 cookie。它只是中间件的 POC,所以我根本不关心代码中的 XSS 风险。
export type OAUTH2Token = {
header: {
alg: string;
typ: string;
};
payload?: {
sub: string;
name: string;
admin: boolean;
};
};
export const saveToken2Cookie: MiddlewareTodo<OAUTH2Token> = params => {
const { action, next } = params;
if (action.type === AUTH_UPDATE_COOKIE && action.payload !== undefined) {
cookie_set('token', JSON.stringify(action.payload));
}
return next(action);
};
Run Code Online (Sandbox Code Playgroud)
最后,这是我的商店配置的外观。
const store: Store<{}> = createStore(
rootReducer,
// applyMiddleware(thunk, oauth2TokenMiddleware(fetch))
applyMiddleware(thunk, createMiddleware<OAUTH2Token>(saveToken2Cookie))
);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8716 次 |
| 最近记录: |