打字稿无法破坏联合类型

时间:2018-08-31 03:18:03

标签: typescript typescript-typings typescript2.0

我的联合类型为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;
  }
};

为什么第一个起作用但第二个为什么不起作用?

3 个答案:

答案 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的任何信息,尽管从技术上讲是可行的。 我猜类型防护只能在直接/从字面上涉及防护表达式的对象上起作用。