我的联合类型为Actions
type Actions = Readonly<{
type: ActionTypes.LOAD_POST;
payload: string;
}> | Readonly<{
type: ActionTypes.LOAD_POST_FAIL;
payload: string;
}> | Readonly<{
type: ActionTypes.LOAD_POST_SUCCESS;
payload: {
url: string;
post: Post;
};
}>
(这是生成的类型,原始类型嵌套有多个类型和ReturnType。)ActionTypes是一个字符串枚举。
const postReducer = (state = initialPostState, action: Actions): PostState => {
const { type, payload } = action;
switch (action.type) {
case ActionTypes.LOAD_POST_SUCCESS: {
const { post } = action.payload; // No error
return { ...state, loading: false, success: true, post };
}
}
switch (type) {
case ActionTypes.LOAD_POST: {
return { ...state, loading: true };
}
case ActionTypes.LOAD_POST_SUCCESS: {
// [ts] Type 'string | { url: string; post: IFullPost; }' has no property 'post' and no string index signature.
const { post } = payload;
return { ...state, loading: false, success: true, post };
}
case ActionTypes.LOAD_POST_FAIL: {
return { ...state, loading: false, success: false, post: null };
}
default:
return state;
}
};
为什么第一个起作用但第二个为什么不起作用?
答案 0 :(得分:0)
您必须打开action.type
才能使action.payload
在case语句中更改其 type 。
答案 1 :(得分:0)
这是设计使然。这是一个非常简化的示例:
type Actions =
{
type: 1,
payload: string;
} |
{
type: 2,
payload: { a: string }
}
function r(action: Actions) {
const { type } = action;
switch (type) {
case 2: {
// Type 'string | { a: string; }' has no property 'a' and no string index signature.
const { a } = action.payload;
}
}
}
当我们破坏action
对象:const { type, payload } = action;
时,我们将丢失破坏类型的耦合信息。之后,type
常量将具有1 | 2
类型,而payload
将具有string | { a: string; }
,即每种类型将基于Actions
类型合并所有可能的选项。这就是TS无法找出payload
确切类型的原因,因为在switch
条件下,我们有绝对独立的变量。
答案 2 :(得分:0)
您正在体验TypeScript通过type guards达到其类型推断的极限。
在您不工作的示例中,TypeScript无法推断出有关已经解构的变量payload
的任何信息,尽管从技术上讲是可行的。
我猜类型防护只能在直接/从字面上涉及防护表达式的对象上起作用。