免责声明:我正在使用https://github.com/iRath96/electron-react-typescript-boilerplate
中的电子样板创建者在其中编写了一些不错的动作代码(从样板中复制粘贴以获得更好的上下文:)
import { Action } from 'redux'
export interface IAction extends Action {}
export interface IActionWithPayload<T> extends IAction {
readonly payload: T
}
interface IActionCreator<T> {
readonly type: string
(payload: T): IActionWithPayload<T>
test(action: IAction): action is IActionWithPayload<T>
}
interface IActionCreatorVoid {
readonly type: string
(): IAction
test(action: IAction): action is IAction
}
export const actionCreator = <T>(type: string): IActionCreator<T> =>
Object.assign((payload: T): IActionWithPayload<T> => ({ type, payload }), {
type,
test(action: IAction): action is IActionWithPayload<T> {
return action.type === type
},
})
export const actionCreatorVoid = (type: string): IActionCreatorVoid =>
Object.assign((): IAction => ({ type }), {
type,
test(action: IAction): action is IAction {
return action.type === type
},
})
所以,要创建新动作,我只需要做:
export const fetchAllBackgroundsPending = actionCreatorVoid('FETCH_BACKGROUNDS_PENDING')
export const fetchAllBackgroundsSuccess = actionCreator<IBackground[]>('FETCH_BACKGROUNDS_SUCCESS')
export const fetchAllBackgroundsRejected = actionCreator<IAPIError>('FETCH_BACKGROUNDS_REJECTED')
它运行得非常完美:我的action.payload
现在已经输入。
但是,如果我在化径器中使用了两个以上的分支,那么我的有效负载上将得到“从不”类型:
const backgroundsReducer = (
state: IBackgroundsState = initialState,
action: IAction
): IBackgroundsState => {
if (fetchAllBackgroundsPending.test(action)) {
return {
...state,
isCollectionLoading: true,
}
}
if (fetchAllBackgroundsSuccess.test(action)) {
return {
...state,
// action has a type of never!
byId: mergeById(state, action.payload)
}
}
return state
}
据我从文档中得知,TS提示我代码分支永远不会运行,但事实并非如此:如果我将console.log
放在那儿,我就可以观察它们!所以,看来TS出了错...还是我呢?
我知道这里提供的代码看起来不像是最小的示例,因此,如果不清楚的话,请告诉我,我将尝试提出一个最小的回购来说明此问题。任何帮助表示赞赏!
答案 0 :(得分:1)
fetchAllBackgroundsPending.test
被声明为user-defined type guard:
test(action: IAction): action is IAction
也就是说,您要告诉TypeScript,假设且仅当参数的类型为test
时,IAction
才返回true。由于action
的{{1}}参数的类型为backgroundsReducer
,因此如果IAction
返回false(表明fetchAllBackgroundsPending.test(action)
不是action
),则IAction
可能没有剩余的类型,因此它的类型为action
。
我相信您对never
的真正需求是TypeScript does not yet support的“单面”类型防护。但是在这种情况下,只需将test
中的test
的返回类型更改为普通的IActionCreatorVoid
(使boolean
不再是用户定义的类型防护, ),因为“真实”情况并不能为该操作确定更具体的类型。我鼓励您针对您使用的样板项目提出问题。
虽然test
的{{1}}方法原则上也应该是单方面的,但当前声明不太可能引起问题,因为在测试类型test
的变量时, “ false”的情况只是将变量保留为IActionCreator
; TypeScript当前尚无法从IAction
中排除IAction
。