Typescript не может уничтожить тип объединения - PullRequest
0 голосов
/ 31 августа 2018

У меня есть тип соединения 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 голосов
/ 08 сентября 2018

Это по замыслу. Вот очень упрощенный пример:

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 мы имеем абсолютно отдельную переменную.

0 голосов
/ 08 сентября 2018

Вы испытываете TypeScript, достигающий пределов своего вывода типа из охранников типа .

В вашем нерабочем примере TypeScript не может ничего сделать с уже деструктурированной переменной payload, хотя это было бы технически выполнимо. Полагаю, охранники типов работают только с объектами, которые прямо / буквально вовлечены в выражение защиты.

0 голосов
/ 31 августа 2018

Вы должны включить action.type, чтобы action.payload сменил свой тип в операторах case.

...