Typescript 如何从redux';s类型定义?

Typescript 如何从redux';s类型定义?,typescript,redux,Typescript,Redux,我有一个使用React和Redux的TypeScript项目,我正在尝试添加一些中间件功能。我从Redux的示例中实现一个开始,如下所示: // ---- middleware.ts ---- export type MiddlewareFunction = (store: any) => (next: any) => (action: any) => any; export class MyMiddleWare { public static Logger: Mid

我有一个使用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);
上面的工作很好,但由于这是TypeScript,我想让它强类型化,理想情况下使用Redux定义的类型,所以我不必重新创建和维护自己的类型。下面是我的index.d.ts文件中用于Redux的相关摘录:

// ---- 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>;
}
/--index.d.ts来自Redux----
导出接口操作{
类型:任意;
}
导出接口调度{
(行动:A):A;
}
导出接口MiddlewareAPI{
调度:调度;
getState():S;
}
导出接口中间件{
(api:MiddlewareAPI):(下一步:调度)=>调度;
}
我正试图找出如何将这些类型引入我的记录器方法,但我运气不太好。在我看来,这样的事情应该奏效:

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);
    };
}
接口MyStore{
东西:绳子;
项目:编号;
}
接口MyAction扩展了Action{
注:字符串;
}
导出类MyMiddleWare{
公共静态记录器:中间件=(api:MiddlewareAPI)=>(下一步:调度)=>(操作:MyAction)=>{
const currentState:MyStore=api.getState();
const newNote:string=action.note;
//做事
返回下一步(操作);
};
}
但是我得到了这个错误:

错误TS2322:Type'(api:MiddlewareAPI)=>(next:Dispatch)=>(action:action)=>action'不可分配给类型“Middleware”。
参数“api”和“api”的类型不兼容。
类型“MiddlewareAPI”不可分配给类型“MiddlewareAPI”。
类型“S”不可分配给类型“MyStore”


我在类型定义中看到了泛型声明,但我尝试了许多不同的组合,似乎无法找到如何将其指定为MyStore,以便在其余声明中识别为泛型类型。例如,根据api声明,getState()应该返回一个MyStore对象。当然,同样的想法也适用于动作类型。

MyStore不是必需的

export const Logger: Middleware =
  (api: MiddlewareAPI<void>) => 
  (next: Dispatch<void>) => 
  <A extends Action>(action: A) => {
    // Do stuff
   return next(action);
  };

拥有一个好的开发工具我有一个解决方案如下:

export type StateType = { thing: string, item: number };

export type ActionType =
    { type: "MY_ACTION", note: string } |
    { type: "PUSH_ACTIVITIY", activity: string };

// Force cast of generic S to my StateType
// tslint:disable-next-line:no-any
function isApi<M>(m: any): m is MiddlewareAPI<StateType> {
    return true;
}

export type MiddlewareFunction =
    (api: MiddlewareAPI<StateType>, next: (action: ActionType) => ActionType, action: ActionType) => ActionType;

export function handleAction(f: MiddlewareFunction): Middleware {
    return <S>(api: MiddlewareAPI<S>) => next => action => {
        if (isApi(api)) {
            // Force cast of generic A to my ActionType
            const _action = (<ActionType>action);
            const _next: (action: ActionType) => ActionType = a => {
                // Force cast my ActionType to generic A
                // tslint:disable-next-line:no-any
                return next(<any>a);
            };
            // Force cast my ActionType to generic A
            // tslint:disable-next-line:no-any
            return f(api, _next, _action) as any;
        } else {
            return next(action);
        }
    };
}
import {
    Store, applyMiddleware, StoreCreator, StoreEnhancer,
    createStore, combineReducers, Middleware, MiddlewareAPI
} from "redux";

const middlewares = [
    dataHandlingMiddleware(datahub),
    loggingMiddleware()];

const rootReducer = combineReducers<StateType>({ ... });
const initialState: StateType = {};

// Trick to enable Redux DevTools with TS: see https://www.npmjs.com/package/redux-ts
const devTool = (f: StoreCreator) => {
    // tslint:disable-next-line:no-any
    return ((window as any).__REDUX_DEVTOOLS_EXTENSION__) ? (window as any).__REDUX_DEVTOOLS_EXTENSION__ : f;
};
const middleware: StoreEnhancer<StateType> = applyMiddleware(...middlewares);
const store: Store<StateType> = middleware(devTool(createStore))(rootReducer, initialState);
请注意,中间件还可能需要在安装过程中传入的附加参数,如服务等(此处为DataHub)。 存储设置如下所示:

export type StateType = { thing: string, item: number };

export type ActionType =
    { type: "MY_ACTION", note: string } |
    { type: "PUSH_ACTIVITIY", activity: string };

// Force cast of generic S to my StateType
// tslint:disable-next-line:no-any
function isApi<M>(m: any): m is MiddlewareAPI<StateType> {
    return true;
}

export type MiddlewareFunction =
    (api: MiddlewareAPI<StateType>, next: (action: ActionType) => ActionType, action: ActionType) => ActionType;

export function handleAction(f: MiddlewareFunction): Middleware {
    return <S>(api: MiddlewareAPI<S>) => next => action => {
        if (isApi(api)) {
            // Force cast of generic A to my ActionType
            const _action = (<ActionType>action);
            const _next: (action: ActionType) => ActionType = a => {
                // Force cast my ActionType to generic A
                // tslint:disable-next-line:no-any
                return next(<any>a);
            };
            // Force cast my ActionType to generic A
            // tslint:disable-next-line:no-any
            return f(api, _next, _action) as any;
        } else {
            return next(action);
        }
    };
}
import {
    Store, applyMiddleware, StoreCreator, StoreEnhancer,
    createStore, combineReducers, Middleware, MiddlewareAPI
} from "redux";

const middlewares = [
    dataHandlingMiddleware(datahub),
    loggingMiddleware()];

const rootReducer = combineReducers<StateType>({ ... });
const initialState: StateType = {};

// Trick to enable Redux DevTools with TS: see https://www.npmjs.com/package/redux-ts
const devTool = (f: StoreCreator) => {
    // tslint:disable-next-line:no-any
    return ((window as any).__REDUX_DEVTOOLS_EXTENSION__) ? (window as any).__REDUX_DEVTOOLS_EXTENSION__ : f;
};
const middleware: StoreEnhancer<StateType> = applyMiddleware(...middlewares);
const store: Store<StateType> = middleware(devTool(createStore))(rootReducer, initialState);
导入{
Store、applyMiddleware、StoreCreator、StoreEnhancer、,
createStore、合并器、中间件、MiddlewareAPI
}来自“redux”;
常数中间件=[
dataHandlingMiddleware(datahub),
日志中间件();
const rootReducer=combinereducer({…});
const initialState:StateType={};
//使用TS启用Redux开发工具的技巧:请参阅https://www.npmjs.com/package/redux-ts
const devTool=(f:StoreCreator)=>{
//tslint:禁用下一行:无任何
返回((任何窗口)。\uuuuRedux\uDevTools\uuuuuuu扩展)?(任何窗口)。\uuuuRedux\uDevTools\uuuuuu扩展:;
};
const中间件:StoreEnhancer=applyMiddleware(…中间件);
const-store:store=中间件(devTool(createStore))(rootReducer,initialState);

希望这能有所帮助。

我刚刚遇到了和你一样的问题

通过将最后一个函数放在括号之间,然后强制其类型为
Dispatch

interface EffectAction扩展操作{
效果(作用:T):无效
}
常量效果:中间件=(api:MiddlewareAPI)=>(下一步:分派)=>((操作:效果操作)=>{
if(action.effect instanceof Function)action.effect(action)
返回下一步(操作)
})作为派遣
以下是我的解决方案:

首先是中间件创建者,它接受todo函数作为输入,作为中间件的核心逻辑运行。todo函数接受一个对象,该对象封装了
store(MiddlewareAPI)
next(Dispatch)
action(action)
以及您的任何其他托管参数。 请注意,我使用
作为中间件
来强制中间件创建者返回中间件。这就是我用来摆脱麻烦的魔法

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;
};
从'redux'导入{MiddlewareAPI,Dispatch,Middleware};
从'redux actions'导入{Action};
导出接口MiddlewareTodoParams{
门店:米德尔瓦雷皮;
下一步:调度;
行动:行动;
[其他属性:字符串]:{};
}
导出接口MiddlewareTodo{
(参数:MiddlewareTodoParams):操作;
}
//(api:MiddlewareAPI):(下一步:调度)=>调度;
导出常量createMiddleware=(
托多:米德尔瓦雷托多,
…args:{}[]
):中间件=>{
退货((门店:MiddlewareAPI)=>{
返回(下一步:发送)=>{
返回操作=>{
log(store.getState(),action.type);
返回todo({store,next,action,…args});
};
};
//使用as中间件强制结果为中间件
})作为中间件;
};
第二部分是我的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);
};
导出类型OAUTH2Token={
标题:{
alg:字符串;
类型:字符串;
};
有效载荷?:{
子:字符串;
名称:字符串;
管理员:布尔;
};
};
导出常量saveToken2Cookie:MiddlewareTodo=params=>{
const{action,next}=params;
if(action.type==AUTH\u UPDATE\u COOKIE&&action.payload!==未定义){
cookie_集('token',JSON.stringify(action.payload));
}
返回下一步(操作);
};
最后,这里是我的商店配置的外观

const store: Store<{}> = createStore(
  rootReducer,
  // applyMiddleware(thunk, oauth2TokenMiddleware(fetch))
  applyMiddleware(thunk, createMiddleware<OAUTH2Token>(saveToken2Cookie))
);
const-store:store=createStore(
减根剂,
//applyMiddleware(thunk、oauth2TokenMiddleware(fetch))
applyMiddleware(thunk,createMiddleware(saveToken2Cookie))
);

以下是一种中间件类型,它使您无需对当前函数进行注释:

import type { Dispatch, AnyAction } from 'redux'

export interface MiddlewareAPI<S, E extends AnyAction> {
  dispatch: Dispatch<E>
  getState(): S
}

export type Middleware<S, E extends AnyAction> =
  (api: MiddlewareAPI<S, E>) =>
  (next: Dispatch<E>) =>
  (event: E) => ReturnType<Dispatch<E>>

const middleware: Middleware<MyStore, MyEvent> = (api) => (next) => (event) => {
  // ...
}
从'redux'导入类型{Dispatch,AnyAction}
出口
import type { Dispatch, AnyAction } from 'redux'

export interface MiddlewareAPI<S, E extends AnyAction> {
  dispatch: Dispatch<E>
  getState(): S
}

export type Middleware<S, E extends AnyAction> =
  (api: MiddlewareAPI<S, E>) =>
  (next: Dispatch<E>) =>
  (event: E) => ReturnType<Dispatch<E>>

const middleware: Middleware<MyStore, MyEvent> = (api) => (next) => (event) => {
  // ...
}