gpt4 book ai didi

javascript - 如何编写不带参数的类型化操作

转载 作者:行者123 更新时间:2023-12-02 21:03:45 24 4
gpt4 key购买 nike

Github 问题表明我们可以使用 TypedAction.defineWithoutPayload 来实现此目的,但我找不到任何有关如何执行此操作的相关示例。

当 accessToken 存储在有效负载中时,我使用它进行登录。如果存在 token ,用户就可以访问私有(private)页面。

export const login = (token: string) => typedAction("LOGIN", token);

现在,在注销按钮上,我尝试实现一个删除有效负载中存储的值的操作。在这种情况下,将没有用于分派(dispatch)操作的参数。那么我该如何编写 typedAction 呢?

如果我使用:

export const logout = () => typedAction("LOGOUT");

我开始在我的 reducer 的有效负载上收到错误,该属性在类型注销时不存在。

这是我的 reducer :

export const tokenReducer = (
state: IState['token'] = null,
{ type, payload }: AppAction,
): typeof state => {
switch (type) {
case 'LOGIN':
return payload;
case 'LOGOUT':
return null;
default:
return state;
}
};

代码沙箱:https://codesandbox.io/s/keen-brook-kntkm?file=/src/store/actions/login.ts:50-118

电子邮件:c@c.com密码:检查

编辑:

export interface IState {
token: string | null;
}
const initialState: IState = {
token: null
};

如果我按照 IDE 的建议使用 state: typeof initialStatestate = initialState,action.payload 会出错:

Type 'string' is not assignable to type 'IState'.ts(2322)

如果我尝试state:initialState那么显然:

'initialState' refers to a value, but is being used as a type here. Did you mean 'typeof initialState'?ts(2749)
``

最佳答案

你拥有typedAction的方式定义的函数工作正常:

export function typedAction<T extends string>(type: T): { type: T };
export function typedAction<T extends string, P extends any>(
type: T,
payload: P
): { type: T; payload: P };
export function typedAction(type: string, payload?: any) {
return { type, payload };
}

您遇到的问题是由于您的 reducer 参数中的操作被解构所致:

export const tokenReducer = (
state: IState["token"] = null,
{ type, payload }: AppAction
): typeof state => {
// ...
};

解构和 TypeScript 的困难之一是,一旦这样做,变量的类型就变得彼此独立。将 Action 解构为{ payload, type }制作 type: 'LOGIN' | 'LOGOUT'payload: string | undefined多变的。即使您稍后细化 type 的值,就像你的 switch 语句中那样,payload仍然有类型 string | undefined ; TypeScript 不会自动优化 payload 的类型在 type 之后的 case block 中是精致的;他们的打字是完全独立的。

因此,您可以使用的一个有点丑陋的技巧是不解构:

export const tokenReducer = (
state: IState['token'] = null,
action: AppAction,
): typeof state => {
switch (action.type) {
case 'LOGIN':
return action.payload;
case 'LOGOUT':
return null;
default:
return state;
}
};

这是有效的,因为在你的 switch 语句中,它能够细化 action: AppAction输入更具体的登录或注销类型,因此 action.payload now 与特定于这些操作之一的有效负载类型密切相关。

这是我使用的 redux 操作的替代模式,您可能会发现更方便 at my fork这让您可以享受映射类型的强大功能,以更少的样板来定义 reducer 。首先,您必须使用类型/有效负载映射定义一个类型,并定义从中派生的一些类型:

export type ActionPayloads = {
LOGIN: string;
LOGOUT: void;
};

export type ActionType = keyof ActionPayloads;

export type Action<T extends ActionType> = {
type: T;
payload: ActionPayloads[T];
};

现在可以根据该 map 定义您的 Action 创建者:

export function typedAction<T extends ActionType>(
type: T,
payload: ActionPayloads[T]
) {
return { type, payload };
}

接下来,您可以定义一个辅助函数来创建强类型化简器:

type ReducerMethods<State> = {
[K in ActionType]?: (state: State, payload: ActionPayloads[K]) => State
};

type Reducer<State> = (state: State, action: AppAction) => State;

function reducer<State>(
initialState: State,
methods: ReducerMethods<State>
): Reducer<State> {
return (state: State = initialState, action: AppAction) => {
const handler: any = methods[action.type];
return handler ? handler(state, action.payload) : state;
};
}

(对于那个丑陋的 : any 转换,我还没有找到一个好的解决方法,但至少我们从逻辑上知道从外部输入的内容是正确的)。

现在您可以为您的操作处理程序使用良好的隐式类型来定义您的 reducer :

type TokenState = string | null;

export const tokenReducer = reducer<TokenState>(null, {
LOGIN: (state, token) => token, // `token` is implicitly typed as `string`
LOGOUT: () => null // TS knows that the payload is `undefined`
});

关于javascript - 如何编写不带参数的类型化操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61275469/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com