如何在 Typescript 中使用 redux-thunk 使用 ThunkAction 正确键入 thunk?
How to properly type a thunk with ThunkAction using redux-thunk in Typescript?
我正在尝试使用 Typescript 检查我的 redux-thunk
代码。
从 Redux 的官方文档:Usage with Redux Thunk,我们得到这个例子:
// src/thunks.ts
import { Action } from 'redux'
import { sendMessage } from './store/chat/actions'
import { RootState } from './store'
import { ThunkAction } from 'redux-thunk'
export const thunkSendMessage = (
message: string
): ThunkAction<void, RootState, unknown, Action<string>> => async dispatch => {
const asyncResp = await exampleAPI()
dispatch(
sendMessage({
message,
user: asyncResp,
timestamp: new Date().getTime()
})
)
}
function exampleAPI() {
return Promise.resolve('Async Chat Bot')
}
为了减少重复,您可能希望在您的存储文件中定义一次可重用的 AppThunk 类型,然后在您编写 thunk 时使用该类型:
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>
问题
我不完全理解 ThunkAction
类型的用法:
ThunkAction<void, RootState, unknown, Action<string>>
有 4 个类型参数,对吗?
第一 - void
这是thunk的return类型,对吧?既然是async
,不应该是Promise<void>
吗?
第二 - RootState
这是完整状态的形状,对吧?我的意思是,它不是切片,而是完整状态。
第三 - unknown
为什么会这样unknown
?这是什么?
第 4 - Action<string>
这个也没看懂。为什么 Action<T>
以字符串作为参数?它应该总是 string
吗?为什么会这样?
其实大部分的答案都可以在source code.
中找到
* @template TReturnType The return type of the thunk's inner function
* @template TState The redux state
* @template TExtraThunkARg Optional extra argument passed to the inner function
* (if specified when setting up the Thunk middleware)
* @template TBasicAction The (non-thunk) actions that can be dispatched.
*/
export type ThunkAction<
TReturnType,
TState,
TExtraThunkArg,
TBasicAction extends Action
> = (
dispatch: ThunkDispatch<TState, TExtraThunkArg, TBasicAction>,
getState: () => TState,
extraArgument: TExtraThunkArg,
) => TReturnType;
第一 - void
thunk 的 return 类型是 NOT 和 Promise
。 return是一个内部函数。因为 inner 函数没有 return 任何东西,所以 return 类型是 void
.
第二 - RootState
是的,没错。参考上面的源代码。具体来说,这一行 * @template TState The redux state
.
第三 - unknown
您阅读了未知 。
第 4 - Action<string>
参考这一行* @template TBasicAction The (non-thunk) actions that can be dispatched.
* @template T the type of the action's `type` tag.
*/
export interface Action<T = any> {
type: T
}
代码片段提取自 here。
Action<T>
接受 string
类型,因为操作类型 IS 一个 string
,而 ThunkAction
类型期望一个Action
此处显示的类型 - TBasicAction extends Action
.
更正
第一 - void
我误解并忘记了 async
函数。请参阅下面的第一条评论。
来自 https://github.com/reduxjs/redux-thunk/blob/d28ab03fd1d2dd1de402928a9589857e97142e09/src/index.d.ts
的打字
/**
* A "thunk" action (a callback function that can be dispatched to the Redux
* store.)
*
* Also known as the "thunk inner function", when used with the typical pattern
* of an action creator function that returns a thunk action.
*
* @template TReturnType The return type of the thunk's inner function
* @template TState The redux state
* @template TExtraThunkARg Optional extra argument passed to the inner function
* (if specified when setting up the Thunk middleware)
* @template TBasicAction The (non-thunk) actions that can be dispatched.
*/
export type ThunkAction<
TReturnType,
TState,
TExtraThunkArg,
TBasicAction extends Action
> = (
dispatch: ThunkDispatch<TState, TExtraThunkArg, TBasicAction>,
getState: () => TState,
extraArgument: TExtraThunkArg,
) => TReturnType;
第一个 - TReturnType
这里我们不关心 return 类型——我们不等待 thunk 的结果。在 TS 中,可以将任何函数分配给 void 签名,因为它不会损害类型安全。 Here's 显示我可以将各种 async/non-async 函数分配给 void 函数签名的示例:
我们使用提供的调度函数来触发我们关心的下一个动作 - 所以在时间方面唯一重要的是我们正在等待某些事情的异步函数内部。 Redux-thunk 内部没有对这个函数的结果做任何事情。这是一个很好的解释器,说明了 thunk 是如何在幕后工作的(只需要预览):
https://frontendmasters.com/courses/rethinking-async-js/synchronous-and-asynchronous-thunks/
第二个 - TState
是的 - 这是整个商店状态类型
第三个 - TExtraThunkARg
您可以添加自己的自定义额外参数,该参数在分派和 getState 之后传递到 thunk 中。这默认为未知,因为除非您明确提供它,否则不清楚它会是什么。这是类型安全的,因为尝试与未知参数交互会导致编译时错误。
更多信息:https://github.com/reduxjs/redux-thunk#injecting-a-custom-argument
第四 - TBasicAction
这是一个动作类型。动作是最基本的动作类型——其中每个 type
属性 都是一个纯字符串。您可以选择提供自己的更具体的类型 - 即 type MyActionType = 'FOO_ACTION' | 'BAR_ACTION'
用于进一步类型 safety/narrowing。然后,您可以将其用作 Action。
我正在尝试使用 Typescript 检查我的 redux-thunk
代码。
从 Redux 的官方文档:Usage with Redux Thunk,我们得到这个例子:
// src/thunks.ts
import { Action } from 'redux'
import { sendMessage } from './store/chat/actions'
import { RootState } from './store'
import { ThunkAction } from 'redux-thunk'
export const thunkSendMessage = (
message: string
): ThunkAction<void, RootState, unknown, Action<string>> => async dispatch => {
const asyncResp = await exampleAPI()
dispatch(
sendMessage({
message,
user: asyncResp,
timestamp: new Date().getTime()
})
)
}
function exampleAPI() {
return Promise.resolve('Async Chat Bot')
}
为了减少重复,您可能希望在您的存储文件中定义一次可重用的 AppThunk 类型,然后在您编写 thunk 时使用该类型:
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>
问题
我不完全理解 ThunkAction
类型的用法:
ThunkAction<void, RootState, unknown, Action<string>>
有 4 个类型参数,对吗?
第一 - void
这是thunk的return类型,对吧?既然是async
,不应该是Promise<void>
吗?
第二 - RootState
这是完整状态的形状,对吧?我的意思是,它不是切片,而是完整状态。
第三 - unknown
为什么会这样unknown
?这是什么?
第 4 - Action<string>
这个也没看懂。为什么 Action<T>
以字符串作为参数?它应该总是 string
吗?为什么会这样?
其实大部分的答案都可以在source code.
中找到 * @template TReturnType The return type of the thunk's inner function
* @template TState The redux state
* @template TExtraThunkARg Optional extra argument passed to the inner function
* (if specified when setting up the Thunk middleware)
* @template TBasicAction The (non-thunk) actions that can be dispatched.
*/
export type ThunkAction<
TReturnType,
TState,
TExtraThunkArg,
TBasicAction extends Action
> = (
dispatch: ThunkDispatch<TState, TExtraThunkArg, TBasicAction>,
getState: () => TState,
extraArgument: TExtraThunkArg,
) => TReturnType;
第一 - void
thunk 的 return 类型是 NOT 和 Promise
。 return是一个内部函数。因为 inner 函数没有 return 任何东西,所以 return 类型是 void
.
第二 - RootState
是的,没错。参考上面的源代码。具体来说,这一行 * @template TState The redux state
.
第三 - unknown
您阅读了未知
第 4 - Action<string>
参考这一行* @template TBasicAction The (non-thunk) actions that can be dispatched.
* @template T the type of the action's `type` tag.
*/
export interface Action<T = any> {
type: T
}
代码片段提取自 here。
Action<T>
接受 string
类型,因为操作类型 IS 一个 string
,而 ThunkAction
类型期望一个Action
此处显示的类型 - TBasicAction extends Action
.
更正
第一 - void
我误解并忘记了 async
函数。请参阅下面的第一条评论。
来自 https://github.com/reduxjs/redux-thunk/blob/d28ab03fd1d2dd1de402928a9589857e97142e09/src/index.d.ts
的打字/**
* A "thunk" action (a callback function that can be dispatched to the Redux
* store.)
*
* Also known as the "thunk inner function", when used with the typical pattern
* of an action creator function that returns a thunk action.
*
* @template TReturnType The return type of the thunk's inner function
* @template TState The redux state
* @template TExtraThunkARg Optional extra argument passed to the inner function
* (if specified when setting up the Thunk middleware)
* @template TBasicAction The (non-thunk) actions that can be dispatched.
*/
export type ThunkAction<
TReturnType,
TState,
TExtraThunkArg,
TBasicAction extends Action
> = (
dispatch: ThunkDispatch<TState, TExtraThunkArg, TBasicAction>,
getState: () => TState,
extraArgument: TExtraThunkArg,
) => TReturnType;
第一个 - TReturnType
这里我们不关心 return 类型——我们不等待 thunk 的结果。在 TS 中,可以将任何函数分配给 void 签名,因为它不会损害类型安全。 Here's 显示我可以将各种 async/non-async 函数分配给 void 函数签名的示例:
我们使用提供的调度函数来触发我们关心的下一个动作 - 所以在时间方面唯一重要的是我们正在等待某些事情的异步函数内部。 Redux-thunk 内部没有对这个函数的结果做任何事情。这是一个很好的解释器,说明了 thunk 是如何在幕后工作的(只需要预览):
https://frontendmasters.com/courses/rethinking-async-js/synchronous-and-asynchronous-thunks/
第二个 - TState 是的 - 这是整个商店状态类型
第三个 - TExtraThunkARg 您可以添加自己的自定义额外参数,该参数在分派和 getState 之后传递到 thunk 中。这默认为未知,因为除非您明确提供它,否则不清楚它会是什么。这是类型安全的,因为尝试与未知参数交互会导致编译时错误。
更多信息:https://github.com/reduxjs/redux-thunk#injecting-a-custom-argument
第四 - TBasicAction
这是一个动作类型。动作是最基本的动作类型——其中每个 type
属性 都是一个纯字符串。您可以选择提供自己的更具体的类型 - 即 type MyActionType = 'FOO_ACTION' | 'BAR_ACTION'
用于进一步类型 safety/narrowing。然后,您可以将其用作 Action。