Typescript 如何从redux';s类型定义?
我有一个使用React和Redux的TypeScript项目,我正在尝试添加一些中间件功能。我从Redux的示例中实现一个开始,如下所示: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
// ---- 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) => {
// ...
}